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.NonNull;
21 import android.annotation.Nullable;
22 import android.compat.annotation.UnsupportedAppUsage;
23 import android.content.ContentResolver;
24 import android.content.Context;
25 import android.content.res.AssetFileDescriptor;
26 import android.graphics.Bitmap;
27 import android.net.Uri;
28 import android.os.Build;
29 import android.os.IBinder;
30 
31 import java.io.FileDescriptor;
32 import java.io.FileInputStream;
33 import java.io.FileNotFoundException;
34 import java.io.IOException;
35 import java.lang.annotation.Retention;
36 import java.lang.annotation.RetentionPolicy;
37 import java.util.List;
38 import java.util.Map;
39 
40 /**
41  * MediaMetadataRetriever class provides a unified interface for retrieving
42  * frame and meta data from an input media file.
43  */
44 public class MediaMetadataRetriever implements AutoCloseable {
45     static {
46         System.loadLibrary("media_jni");
native_init()47         native_init();
48     }
49 
50     // The field below is accessed by native methods
51     @SuppressWarnings("unused")
52     private long mNativeContext;
53 
54     private static final int EMBEDDED_PICTURE_TYPE_ANY = 0xFFFF;
55 
MediaMetadataRetriever()56     public MediaMetadataRetriever() {
57         native_setup();
58     }
59 
60     /**
61      * Sets the data source (file pathname) to use. Call this
62      * method before the rest of the methods in this class. This method may be
63      * time-consuming.
64      *
65      * @param path The path of the input media file.
66      * @throws IllegalArgumentException If the path is invalid.
67      */
setDataSource(String path)68     public void setDataSource(String path) throws IllegalArgumentException {
69         if (path == null) {
70             throw new IllegalArgumentException();
71         }
72 
73         try (FileInputStream is = new FileInputStream(path)) {
74             FileDescriptor fd = is.getFD();
75             setDataSource(fd, 0, 0x7ffffffffffffffL);
76         } catch (FileNotFoundException fileEx) {
77             throw new IllegalArgumentException();
78         } catch (IOException ioEx) {
79             throw new IllegalArgumentException();
80         }
81     }
82 
83     /**
84      * Sets the data source (URI) to use. Call this
85      * method before the rest of the methods in this class. This method may be
86      * time-consuming.
87      *
88      * @param uri The URI of the input media.
89      * @param headers the headers to be sent together with the request for the data
90      * @throws IllegalArgumentException If the URI is invalid.
91      */
setDataSource(String uri, Map<String, String> headers)92     public void setDataSource(String uri,  Map<String, String> headers)
93             throws IllegalArgumentException {
94         int i = 0;
95         String[] keys = new String[headers.size()];
96         String[] values = new String[headers.size()];
97         for (Map.Entry<String, String> entry: headers.entrySet()) {
98             keys[i] = entry.getKey();
99             values[i] = entry.getValue();
100             ++i;
101         }
102 
103         _setDataSource(
104                 MediaHTTPService.createHttpServiceBinderIfNecessary(uri),
105                 uri,
106                 keys,
107                 values);
108     }
109 
_setDataSource( IBinder httpServiceBinder, String uri, String[] keys, String[] values)110     private native void _setDataSource(
111         IBinder httpServiceBinder, String uri, String[] keys, String[] values)
112         throws IllegalArgumentException;
113 
114     /**
115      * Sets the data source (FileDescriptor) to use.  It is the caller's
116      * responsibility to close the file descriptor. It is safe to do so as soon
117      * as this call returns. Call this method before the rest of the methods in
118      * this class. This method may be time-consuming.
119      *
120      * @param fd the FileDescriptor for the file you want to play
121      * @param offset the offset into the file where the data to be played starts,
122      * in bytes. It must be non-negative
123      * @param length the length in bytes of the data to be played. It must be
124      * non-negative.
125      * @throws IllegalArgumentException if the arguments are invalid
126      */
setDataSource(FileDescriptor fd, long offset, long length)127     public native void setDataSource(FileDescriptor fd, long offset, long length)
128             throws IllegalArgumentException;
129 
130     /**
131      * Sets the data source (FileDescriptor) to use. It is the caller's
132      * responsibility to close the file descriptor. It is safe to do so as soon
133      * as this call returns. Call this method before the rest of the methods in
134      * this class. This method may be time-consuming.
135      *
136      * @param fd the FileDescriptor for the file you want to play
137      * @throws IllegalArgumentException if the FileDescriptor is invalid
138      */
setDataSource(FileDescriptor fd)139     public void setDataSource(FileDescriptor fd)
140             throws IllegalArgumentException {
141         // intentionally less than LONG_MAX
142         setDataSource(fd, 0, 0x7ffffffffffffffL);
143     }
144 
145     /**
146      * Sets the data source as a content Uri. Call this method before
147      * the rest of the methods in this class. This method may be time-consuming.
148      *
149      * @param context the Context to use when resolving the Uri
150      * @param uri the Content URI of the data you want to play
151      * @throws IllegalArgumentException if the Uri is invalid
152      * @throws SecurityException if the Uri cannot be used due to lack of
153      * permission.
154      */
setDataSource(Context context, Uri uri)155     public void setDataSource(Context context, Uri uri)
156         throws IllegalArgumentException, SecurityException {
157         if (uri == null) {
158             throw new IllegalArgumentException();
159         }
160 
161         String scheme = uri.getScheme();
162         if(scheme == null || scheme.equals("file")) {
163             setDataSource(uri.getPath());
164             return;
165         }
166 
167         AssetFileDescriptor fd = null;
168         try {
169             ContentResolver resolver = context.getContentResolver();
170             try {
171                 fd = resolver.openAssetFileDescriptor(uri, "r");
172             } catch(FileNotFoundException e) {
173                 throw new IllegalArgumentException();
174             }
175             if (fd == null) {
176                 throw new IllegalArgumentException();
177             }
178             FileDescriptor descriptor = fd.getFileDescriptor();
179             if (!descriptor.valid()) {
180                 throw new IllegalArgumentException();
181             }
182             // Note: using getDeclaredLength so that our behavior is the same
183             // as previous versions when the content provider is returning
184             // a full file.
185             if (fd.getDeclaredLength() < 0) {
186                 setDataSource(descriptor);
187             } else {
188                 setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength());
189             }
190             return;
191         } catch (SecurityException ex) {
192         } finally {
193             try {
194                 if (fd != null) {
195                     fd.close();
196                 }
197             } catch(IOException ioEx) {
198             }
199         }
200         setDataSource(uri.toString());
201     }
202 
203     /**
204      * Sets the data source (MediaDataSource) to use.
205      *
206      * @param dataSource the MediaDataSource for the media you want to play
207      */
setDataSource(MediaDataSource dataSource)208     public void setDataSource(MediaDataSource dataSource)
209             throws IllegalArgumentException {
210         _setDataSource(dataSource);
211     }
212 
_setDataSource(MediaDataSource dataSource)213     private native void _setDataSource(MediaDataSource dataSource)
214           throws IllegalArgumentException;
215 
216     /**
217      * Call this method after setDataSource(). This method retrieves the
218      * meta data value associated with the keyCode.
219      *
220      * The keyCode currently supported is listed below as METADATA_XXX
221      * constants. With any other value, it returns a null pointer.
222      *
223      * @param keyCode One of the constants listed below at the end of the class.
224      * @return The meta data value associate with the given keyCode on success;
225      * null on failure.
226      */
extractMetadata(int keyCode)227     public native String extractMetadata(int keyCode);
228 
229     /**
230      * Call this method after setDataSource(). This method finds a
231      * representative frame close to the given time position by considering
232      * the given option if possible, and returns it as a bitmap.
233      *
234      * <p>If you don't need a full-resolution
235      * frame (for example, because you need a thumbnail image), use
236      * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this
237      * method.</p>
238      *
239      * @param timeUs The time position where the frame will be retrieved.
240      * When retrieving the frame at the given time position, there is no
241      * guarantee that the data source has a frame located at the position.
242      * When this happens, a frame nearby will be returned. If timeUs is
243      * negative, time position and option will ignored, and any frame
244      * that the implementation considers as representative may be returned.
245      *
246      * @param option a hint on how the frame is found. Use
247      * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame
248      * that has a timestamp earlier than or the same as timeUs. Use
249      * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame
250      * that has a timestamp later than or the same as timeUs. Use
251      * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame
252      * that has a timestamp closest to or the same as timeUs. Use
253      * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may
254      * or may not be a sync frame but is closest to or the same as timeUs.
255      * {@link #OPTION_CLOSEST} often has larger performance overhead compared
256      * to the other options if there is no sync frame located at timeUs.
257      *
258      * @return A Bitmap containing a representative video frame, which
259      *         can be null, if such a frame cannot be retrieved.
260      */
getFrameAtTime(long timeUs, @Option int option)261     public Bitmap getFrameAtTime(long timeUs, @Option int option) {
262         if (option < OPTION_PREVIOUS_SYNC ||
263             option > OPTION_CLOSEST) {
264             throw new IllegalArgumentException("Unsupported option: " + option);
265         }
266 
267         return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/);
268     }
269 
270     /**
271      * Retrieve a video frame near a given timestamp scaled to a desired size.
272      * Call this method after setDataSource(). This method finds a representative
273      * frame close to the given time position by considering the given option
274      * if possible, and returns it as a bitmap with same aspect ratio as the source
275      * while scaling it so that it fits into the desired size of dst_width by dst_height.
276      * This is useful for generating a thumbnail for an input data source or just to
277      * obtain a scaled frame at the given time position.
278      *
279      * @param timeUs The time position in microseconds where the frame will be retrieved.
280      * When retrieving the frame at the given time position, there is no
281      * guarantee that the data source has a frame located at the position.
282      * When this happens, a frame nearby will be returned. If timeUs is
283      * negative, time position and option will ignored, and any frame
284      * that the implementation considers as representative may be returned.
285      *
286      * @param option a hint on how the frame is found. Use
287      * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame
288      * that has a timestamp earlier than or the same as timeUs. Use
289      * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame
290      * that has a timestamp later than or the same as timeUs. Use
291      * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame
292      * that has a timestamp closest to or the same as timeUs. Use
293      * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may
294      * or may not be a sync frame but is closest to or the same as timeUs.
295      * {@link #OPTION_CLOSEST} often has larger performance overhead compared
296      * to the other options if there is no sync frame located at timeUs.
297      *
298      * @param dstWidth expected output bitmap width
299      * @param dstHeight expected output bitmap height
300      * @return A Bitmap of size not larger than dstWidth by dstHeight containing a
301      *         scaled video frame, which can be null, if such a frame cannot be retrieved.
302      * @throws IllegalArgumentException if passed in invalid option or width by height
303      *         is less than or equal to 0.
304      */
getScaledFrameAtTime( long timeUs, @Option int option, int dstWidth, int dstHeight)305     public Bitmap getScaledFrameAtTime(
306             long timeUs, @Option int option, int dstWidth, int dstHeight) {
307         if (option < OPTION_PREVIOUS_SYNC ||
308             option > OPTION_CLOSEST) {
309             throw new IllegalArgumentException("Unsupported option: " + option);
310         }
311         if (dstWidth <= 0) {
312             throw new IllegalArgumentException("Invalid width: " + dstWidth);
313         }
314         if (dstHeight <= 0) {
315             throw new IllegalArgumentException("Invalid height: " + dstHeight);
316         }
317 
318         return _getFrameAtTime(timeUs, option, dstWidth, dstHeight);
319     }
320 
321     /**
322      * Call this method after setDataSource(). This method finds a
323      * representative frame close to the given time position if possible,
324      * and returns it as a bitmap. Call this method if one does not care
325      * how the frame is found as long as it is close to the given time;
326      * otherwise, please call {@link #getFrameAtTime(long, int)}.
327      *
328      * <p>If you don't need a full-resolution
329      * frame (for example, because you need a thumbnail image), use
330      * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this
331      * method.</p>
332      *
333      * @param timeUs The time position where the frame will be retrieved.
334      * When retrieving the frame at the given time position, there is no
335      * guarentee that the data source has a frame located at the position.
336      * When this happens, a frame nearby will be returned. If timeUs is
337      * negative, time position and option will ignored, and any frame
338      * that the implementation considers as representative may be returned.
339      *
340      * @return A Bitmap of size dst_widthxdst_height containing a representative
341      *         video frame, which can be null, if such a frame cannot be retrieved.
342      *
343      * @see #getFrameAtTime(long, int)
344      */
getFrameAtTime(long timeUs)345     public Bitmap getFrameAtTime(long timeUs) {
346         return getFrameAtTime(timeUs, OPTION_CLOSEST_SYNC);
347     }
348 
349     /**
350      * Call this method after setDataSource(). This method finds a
351      * representative frame at any time position if possible,
352      * and returns it as a bitmap. Call this method if one does not
353      * care about where the frame is located; otherwise, please call
354      * {@link #getFrameAtTime(long)} or {@link #getFrameAtTime(long, int)}
355      *
356      * <p>If you don't need a full-resolution
357      * frame (for example, because you need a thumbnail image), use
358      * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this
359      * method.</p>
360      *
361      * @return A Bitmap containing a representative video frame, which
362      *         can be null, if such a frame cannot be retrieved.
363      *
364      * @see #getFrameAtTime(long)
365      * @see #getFrameAtTime(long, int)
366      */
getFrameAtTime()367     public Bitmap getFrameAtTime() {
368         return _getFrameAtTime(-1, OPTION_CLOSEST_SYNC, -1 /*dst_width*/, -1 /*dst_height*/);
369     }
370 
_getFrameAtTime(long timeUs, int option, int width, int height)371     private native Bitmap _getFrameAtTime(long timeUs, int option, int width, int height);
372 
373     public static final class BitmapParams {
374         private Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
375         private Bitmap.Config outActualConfig = Bitmap.Config.ARGB_8888;
376 
377         /**
378          * Create a default BitmapParams object. By default, it uses {@link Bitmap.Config#ARGB_8888}
379          * as the preferred bitmap config.
380          */
BitmapParams()381         public BitmapParams() {}
382 
383         /**
384          * Set the preferred bitmap config for the decoder to decode into.
385          *
386          * If not set, or the request cannot be met, the decoder will output
387          * in {@link Bitmap.Config#ARGB_8888} config by default.
388          *
389          * After decode, the actual config used can be retrieved by {@link #getActualConfig()}.
390          *
391          * @param config the preferred bitmap config to use.
392          */
setPreferredConfig(@onNull Bitmap.Config config)393         public void setPreferredConfig(@NonNull Bitmap.Config config) {
394             if (config == null) {
395                 throw new IllegalArgumentException("preferred config can't be null");
396             }
397             inPreferredConfig = config;
398         }
399 
400         /**
401          * Retrieve the preferred bitmap config in the params.
402          *
403          * @return the preferred bitmap config.
404          */
getPreferredConfig()405         public @NonNull Bitmap.Config getPreferredConfig() {
406             return inPreferredConfig;
407         }
408 
409         /**
410          * Get the actual bitmap config used to decode the bitmap after the decoding.
411          *
412          * @return the actual bitmap config used.
413          */
getActualConfig()414         public @NonNull Bitmap.Config getActualConfig() {
415             return outActualConfig;
416         }
417     }
418 
419     /**
420      * This method retrieves a video frame by its index. It should only be called
421      * after {@link #setDataSource}.
422      *
423      * After the bitmap is returned, you can query the actual parameters that were
424      * used to create the bitmap from the {@code BitmapParams} argument, for instance
425      * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
426      *
427      * @param frameIndex 0-based index of the video frame. The frame index must be that of
428      *        a valid frame. The total number of frames available for retrieval can be queried
429      *        via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
430      * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
431      *
432      * @throws IllegalStateException if the container doesn't contain video or image sequences.
433      * @throws IllegalArgumentException if the requested frame index does not exist.
434      *
435      * @return A Bitmap containing the requested video frame, or null if the retrieval fails.
436      *
437      * @see #getFrameAtIndex(int)
438      * @see #getFramesAtIndex(int, int, BitmapParams)
439      * @see #getFramesAtIndex(int, int)
440      */
getFrameAtIndex(int frameIndex, @NonNull BitmapParams params)441     public Bitmap getFrameAtIndex(int frameIndex, @NonNull BitmapParams params) {
442         List<Bitmap> bitmaps = getFramesAtIndex(frameIndex, 1, params);
443         return bitmaps.get(0);
444     }
445 
446     /**
447      * This method is similar to {@link #getFrameAtIndex(int, BitmapParams)} except that
448      * the default for {@link BitmapParams} will be used.
449      *
450      * @param frameIndex 0-based index of the video frame. The frame index must be that of
451      *        a valid frame. The total number of frames available for retrieval can be queried
452      *        via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
453      *
454      * @throws IllegalStateException if the container doesn't contain video or image sequences.
455      * @throws IllegalArgumentException if the requested frame index does not exist.
456      *
457      * @return A Bitmap containing the requested video frame, or null if the retrieval fails.
458      *
459      * @see #getFrameAtIndex(int, BitmapParams)
460      * @see #getFramesAtIndex(int, int, BitmapParams)
461      * @see #getFramesAtIndex(int, int)
462      */
getFrameAtIndex(int frameIndex)463     public Bitmap getFrameAtIndex(int frameIndex) {
464         List<Bitmap> bitmaps = getFramesAtIndex(frameIndex, 1);
465         return bitmaps.get(0);
466     }
467 
468     /**
469      * This method retrieves a consecutive set of video frames starting at the
470      * specified index. It should only be called after {@link #setDataSource}.
471      *
472      * If the caller intends to retrieve more than one consecutive video frames,
473      * this method is preferred over {@link #getFrameAtIndex(int, BitmapParams)} for efficiency.
474      *
475      * After the bitmaps are returned, you can query the actual parameters that were
476      * used to create the bitmaps from the {@code BitmapParams} argument, for instance
477      * to query the bitmap config used for the bitmaps with {@link BitmapParams#getActualConfig}.
478      *
479      * @param frameIndex 0-based index of the first video frame to retrieve. The frame index
480      *        must be that of a valid frame. The total number of frames available for retrieval
481      *        can be queried via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
482      * @param numFrames number of consecutive video frames to retrieve. Must be a positive
483      *        value. The stream must contain at least numFrames frames starting at frameIndex.
484      * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
485      *
486      * @throws IllegalStateException if the container doesn't contain video or image sequences.
487      * @throws IllegalArgumentException if the frameIndex or numFrames is invalid, or the
488      *         stream doesn't contain at least numFrames starting at frameIndex.
489 
490      * @return An list of Bitmaps containing the requested video frames. The returned
491      *         array could contain less frames than requested if the retrieval fails.
492      *
493      * @see #getFrameAtIndex(int, BitmapParams)
494      * @see #getFrameAtIndex(int)
495      * @see #getFramesAtIndex(int, int)
496      */
getFramesAtIndex( int frameIndex, int numFrames, @NonNull BitmapParams params)497     public @NonNull List<Bitmap> getFramesAtIndex(
498             int frameIndex, int numFrames, @NonNull BitmapParams params) {
499         return getFramesAtIndexInternal(frameIndex, numFrames, params);
500     }
501 
502     /**
503      * This method is similar to {@link #getFramesAtIndex(int, int, BitmapParams)} except that
504      * the default for {@link BitmapParams} will be used.
505      *
506      * @param frameIndex 0-based index of the first video frame to retrieve. The frame index
507      *        must be that of a valid frame. The total number of frames available for retrieval
508      *        can be queried via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
509      * @param numFrames number of consecutive video frames to retrieve. Must be a positive
510      *        value. The stream must contain at least numFrames frames starting at frameIndex.
511      *
512      * @throws IllegalStateException if the container doesn't contain video or image sequences.
513      * @throws IllegalArgumentException if the frameIndex or numFrames is invalid, or the
514      *         stream doesn't contain at least numFrames starting at frameIndex.
515 
516      * @return An list of Bitmaps containing the requested video frames. The returned
517      *         array could contain less frames than requested if the retrieval fails.
518      *
519      * @see #getFrameAtIndex(int, BitmapParams)
520      * @see #getFrameAtIndex(int)
521      * @see #getFramesAtIndex(int, int, BitmapParams)
522      */
getFramesAtIndex(int frameIndex, int numFrames)523     public @NonNull List<Bitmap> getFramesAtIndex(int frameIndex, int numFrames) {
524         return getFramesAtIndexInternal(frameIndex, numFrames, null);
525     }
526 
getFramesAtIndexInternal( int frameIndex, int numFrames, @Nullable BitmapParams params)527     private @NonNull List<Bitmap> getFramesAtIndexInternal(
528             int frameIndex, int numFrames, @Nullable BitmapParams params) {
529         if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO))) {
530             throw new IllegalStateException("Does not contail video or image sequences");
531         }
532         int frameCount = Integer.parseInt(
533                 extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT));
534         if (frameIndex < 0 || numFrames < 1
535                 || frameIndex >= frameCount
536                 || frameIndex > frameCount - numFrames) {
537             throw new IllegalArgumentException("Invalid frameIndex or numFrames: "
538                 + frameIndex + ", " + numFrames);
539         }
540         return _getFrameAtIndex(frameIndex, numFrames, params);
541     }
542 
_getFrameAtIndex( int frameIndex, int numFrames, @Nullable BitmapParams params)543     private native @NonNull List<Bitmap> _getFrameAtIndex(
544             int frameIndex, int numFrames, @Nullable BitmapParams params);
545 
546     /**
547      * This method retrieves a still image by its index. It should only be called
548      * after {@link #setDataSource}.
549      *
550      * After the bitmap is returned, you can query the actual parameters that were
551      * used to create the bitmap from the {@code BitmapParams} argument, for instance
552      * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
553      *
554      * @param imageIndex 0-based index of the image.
555      * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
556      *
557      * @throws IllegalStateException if the container doesn't contain still images.
558      * @throws IllegalArgumentException if the requested image does not exist.
559      *
560      * @return the requested still image, or null if the image cannot be retrieved.
561      *
562      * @see #getImageAtIndex(int)
563      * @see #getPrimaryImage(BitmapParams)
564      * @see #getPrimaryImage()
565      */
getImageAtIndex(int imageIndex, @NonNull BitmapParams params)566     public Bitmap getImageAtIndex(int imageIndex, @NonNull BitmapParams params) {
567         return getImageAtIndexInternal(imageIndex, params);
568     }
569 
570     /**
571      * @hide
572      *
573      * This method retrieves the thumbnail image for a still image if it's available.
574      * It should only be called after {@link #setDataSource}.
575      *
576      * @param imageIndex 0-based index of the image, negative value indicates primary image.
577      * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
578      * @param targetSize intended size of one edge (wdith or height) of the thumbnail,
579      *                   this is a heuristic for the framework to decide whether the embedded
580      *                   thumbnail should be used.
581      * @param maxPixels maximum pixels of thumbnail, this is a heuristic for the frameowrk to
582      *                  decide whehther the embedded thumnbail (or a downscaled version of it)
583      *                  should be used.
584      * @return the retrieved thumbnail, or null if no suitable thumbnail is available.
585      */
getThumbnailImageAtIndex( int imageIndex, @NonNull BitmapParams params, int targetSize, int maxPixels)586     public native @Nullable Bitmap getThumbnailImageAtIndex(
587             int imageIndex, @NonNull BitmapParams params, int targetSize, int maxPixels);
588 
589     /**
590      * This method is similar to {@link #getImageAtIndex(int, BitmapParams)} except that
591      * the default for {@link BitmapParams} will be used.
592      *
593      * @param imageIndex 0-based index of the image.
594      *
595      * @throws IllegalStateException if the container doesn't contain still images.
596      * @throws IllegalArgumentException if the requested image does not exist.
597      *
598      * @return the requested still image, or null if the image cannot be retrieved.
599      *
600      * @see #getImageAtIndex(int, BitmapParams)
601      * @see #getPrimaryImage(BitmapParams)
602      * @see #getPrimaryImage()
603      */
getImageAtIndex(int imageIndex)604     public Bitmap getImageAtIndex(int imageIndex) {
605         return getImageAtIndexInternal(imageIndex, null);
606     }
607 
608     /**
609      * This method retrieves the primary image of the media content. It should only
610      * be called after {@link #setDataSource}.
611      *
612      * After the bitmap is returned, you can query the actual parameters that were
613      * used to create the bitmap from the {@code BitmapParams} argument, for instance
614      * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
615      *
616      * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
617      *
618      * @return the primary image, or null if it cannot be retrieved.
619      *
620      * @throws IllegalStateException if the container doesn't contain still images.
621      *
622      * @see #getImageAtIndex(int, BitmapParams)
623      * @see #getImageAtIndex(int)
624      * @see #getPrimaryImage()
625      */
getPrimaryImage(@onNull BitmapParams params)626     public Bitmap getPrimaryImage(@NonNull BitmapParams params) {
627         return getImageAtIndexInternal(-1, params);
628     }
629 
630     /**
631      * This method is similar to {@link #getPrimaryImage(BitmapParams)} except that
632      * the default for {@link BitmapParams} will be used.
633      *
634      * @return the primary image, or null if it cannot be retrieved.
635      *
636      * @throws IllegalStateException if the container doesn't contain still images.
637      *
638      * @see #getImageAtIndex(int, BitmapParams)
639      * @see #getImageAtIndex(int)
640      * @see #getPrimaryImage(BitmapParams)
641      */
getPrimaryImage()642     public Bitmap getPrimaryImage() {
643         return getImageAtIndexInternal(-1, null);
644     }
645 
getImageAtIndexInternal(int imageIndex, @Nullable BitmapParams params)646     private Bitmap getImageAtIndexInternal(int imageIndex, @Nullable BitmapParams params) {
647         if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE))) {
648             throw new IllegalStateException("Does not contail still images");
649         }
650 
651         String imageCount = extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT);
652         if (imageIndex >= Integer.parseInt(imageCount)) {
653             throw new IllegalArgumentException("Invalid image index: " + imageCount);
654         }
655 
656         return _getImageAtIndex(imageIndex, params);
657     }
658 
_getImageAtIndex(int imageIndex, @Nullable BitmapParams params)659     private native Bitmap _getImageAtIndex(int imageIndex, @Nullable BitmapParams params);
660 
661     /**
662      * Call this method after setDataSource(). This method finds the optional
663      * graphic or album/cover art associated associated with the data source. If
664      * there are more than one pictures, (any) one of them is returned.
665      *
666      * @return null if no such graphic is found.
667      */
getEmbeddedPicture()668     public byte[] getEmbeddedPicture() {
669         return getEmbeddedPicture(EMBEDDED_PICTURE_TYPE_ANY);
670     }
671 
672     @UnsupportedAppUsage
getEmbeddedPicture(int pictureType)673     private native byte[] getEmbeddedPicture(int pictureType);
674 
675     @Override
close()676     public void close() {
677         release();
678     }
679 
680     /**
681      * Call it when one is done with the object. This method releases the memory
682      * allocated internally.
683      */
release()684     public native void release();
685     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
native_setup()686     private native void native_setup();
687     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
native_init()688     private static native void native_init();
689 
690     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
native_finalize()691     private native final void native_finalize();
692 
693     @Override
finalize()694     protected void finalize() throws Throwable {
695         try {
696             native_finalize();
697         } finally {
698             super.finalize();
699         }
700     }
701 
702     /**
703      * Option used in method {@link #getFrameAtTime(long, int)} to get a
704      * frame at a specified location.
705      *
706      * @see #getFrameAtTime(long, int)
707      */
708     /* Do not change these option values without updating their counterparts
709      * in include/media/MediaSource.h!
710      */
711     /**
712      * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
713      * a sync (or key) frame associated with a data source that is located
714      * right before or at the given time.
715      *
716      * @see #getFrameAtTime(long, int)
717      */
718     public static final int OPTION_PREVIOUS_SYNC    = 0x00;
719     /**
720      * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
721      * a sync (or key) frame associated with a data source that is located
722      * right after or at the given time.
723      *
724      * @see #getFrameAtTime(long, int)
725      */
726     public static final int OPTION_NEXT_SYNC        = 0x01;
727     /**
728      * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
729      * a sync (or key) frame associated with a data source that is located
730      * closest to (in time) or at the given time.
731      *
732      * @see #getFrameAtTime(long, int)
733      */
734     public static final int OPTION_CLOSEST_SYNC     = 0x02;
735     /**
736      * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
737      * a frame (not necessarily a key frame) associated with a data source that
738      * is located closest to or at the given time.
739      *
740      * @see #getFrameAtTime(long, int)
741      */
742     public static final int OPTION_CLOSEST          = 0x03;
743 
744     /** @hide */
745     @IntDef(flag = true, prefix = { "OPTION_" }, value = {
746             OPTION_PREVIOUS_SYNC,
747             OPTION_NEXT_SYNC,
748             OPTION_CLOSEST_SYNC,
749             OPTION_CLOSEST,
750     })
751     @Retention(RetentionPolicy.SOURCE)
752     public @interface Option {}
753 
754     /*
755      * Do not change these metadata key values without updating their
756      * counterparts in include/media/mediametadataretriever.h!
757      */
758     /**
759      * The metadata key to retrieve the numeric string describing the
760      * order of the audio data source on its original recording.
761      */
762     public static final int METADATA_KEY_CD_TRACK_NUMBER = 0;
763     /**
764      * The metadata key to retrieve the information about the album title
765      * of the data source.
766      */
767     public static final int METADATA_KEY_ALBUM           = 1;
768     /**
769      * The metadata key to retrieve the information about the artist of
770      * the data source.
771      */
772     public static final int METADATA_KEY_ARTIST          = 2;
773     /**
774      * The metadata key to retrieve the information about the author of
775      * the data source.
776      */
777     public static final int METADATA_KEY_AUTHOR          = 3;
778     /**
779      * The metadata key to retrieve the information about the composer of
780      * the data source.
781      */
782     public static final int METADATA_KEY_COMPOSER        = 4;
783     /**
784      * The metadata key to retrieve the date when the data source was created
785      * or modified.
786      */
787     public static final int METADATA_KEY_DATE            = 5;
788     /**
789      * The metadata key to retrieve the content type or genre of the data
790      * source.
791      */
792     public static final int METADATA_KEY_GENRE           = 6;
793     /**
794      * The metadata key to retrieve the data source title.
795      */
796     public static final int METADATA_KEY_TITLE           = 7;
797     /**
798      * The metadata key to retrieve the year when the data source was created
799      * or modified.
800      */
801     public static final int METADATA_KEY_YEAR            = 8;
802     /**
803      * The metadata key to retrieve the playback duration of the data source.
804      */
805     public static final int METADATA_KEY_DURATION        = 9;
806     /**
807      * The metadata key to retrieve the number of tracks, such as audio, video,
808      * text, in the data source, such as a mp4 or 3gpp file.
809      */
810     public static final int METADATA_KEY_NUM_TRACKS      = 10;
811     /**
812      * The metadata key to retrieve the information of the writer (such as
813      * lyricist) of the data source.
814      */
815     public static final int METADATA_KEY_WRITER          = 11;
816     /**
817      * The metadata key to retrieve the mime type of the data source. Some
818      * example mime types include: "video/mp4", "audio/mp4", "audio/amr-wb",
819      * etc.
820      */
821     public static final int METADATA_KEY_MIMETYPE        = 12;
822     /**
823      * The metadata key to retrieve the information about the performers or
824      * artist associated with the data source.
825      */
826     public static final int METADATA_KEY_ALBUMARTIST     = 13;
827     /**
828      * The metadata key to retrieve the numberic string that describes which
829      * part of a set the audio data source comes from.
830      */
831     public static final int METADATA_KEY_DISC_NUMBER     = 14;
832     /**
833      * The metadata key to retrieve the music album compilation status.
834      */
835     public static final int METADATA_KEY_COMPILATION     = 15;
836     /**
837      * If this key exists the media contains audio content.
838      */
839     public static final int METADATA_KEY_HAS_AUDIO       = 16;
840     /**
841      * If this key exists the media contains video content.
842      */
843     public static final int METADATA_KEY_HAS_VIDEO       = 17;
844     /**
845      * If the media contains video, this key retrieves its width.
846      */
847     public static final int METADATA_KEY_VIDEO_WIDTH     = 18;
848     /**
849      * If the media contains video, this key retrieves its height.
850      */
851     public static final int METADATA_KEY_VIDEO_HEIGHT    = 19;
852     /**
853      * This key retrieves the average bitrate (in bits/sec), if available.
854      */
855     public static final int METADATA_KEY_BITRATE         = 20;
856     /**
857      * This key retrieves the language code of text tracks, if available.
858      * If multiple text tracks present, the return value will look like:
859      * "eng:chi"
860      * @hide
861      */
862     public static final int METADATA_KEY_TIMED_TEXT_LANGUAGES      = 21;
863     /**
864      * If this key exists the media is drm-protected.
865      * @hide
866      */
867     public static final int METADATA_KEY_IS_DRM          = 22;
868     /**
869      * This key retrieves the location information, if available.
870      * The location should be specified according to ISO-6709 standard, under
871      * a mp4/3gp box "@xyz". Location with longitude of -90 degrees and latitude
872      * of 180 degrees will be retrieved as "+180.0000-90.0000/", for instance.
873      */
874     public static final int METADATA_KEY_LOCATION        = 23;
875     /**
876      * This key retrieves the video rotation angle in degrees, if available.
877      * The video rotation angle may be 0, 90, 180, or 270 degrees.
878      */
879     public static final int METADATA_KEY_VIDEO_ROTATION = 24;
880     /**
881      * This key retrieves the original capture framerate, if it's
882      * available. The capture framerate will be a floating point
883      * number.
884      */
885     public static final int METADATA_KEY_CAPTURE_FRAMERATE = 25;
886     /**
887      * If this key exists the media contains still image content.
888      */
889     public static final int METADATA_KEY_HAS_IMAGE       = 26;
890     /**
891      * If the media contains still images, this key retrieves the number
892      * of still images.
893      */
894     public static final int METADATA_KEY_IMAGE_COUNT     = 27;
895     /**
896      * If the media contains still images, this key retrieves the image
897      * index of the primary image.
898      */
899     public static final int METADATA_KEY_IMAGE_PRIMARY   = 28;
900     /**
901      * If the media contains still images, this key retrieves the width
902      * of the primary image.
903      */
904     public static final int METADATA_KEY_IMAGE_WIDTH     = 29;
905     /**
906      * If the media contains still images, this key retrieves the height
907      * of the primary image.
908      */
909     public static final int METADATA_KEY_IMAGE_HEIGHT    = 30;
910     /**
911      * If the media contains still images, this key retrieves the rotation
912      * angle (in degrees clockwise) of the primary image. The image rotation
913      * angle must be one of 0, 90, 180, or 270 degrees.
914      */
915     public static final int METADATA_KEY_IMAGE_ROTATION  = 31;
916     /**
917      * If the media contains video and this key exists, it retrieves the
918      * total number of frames in the video sequence.
919      */
920     public static final int METADATA_KEY_VIDEO_FRAME_COUNT = 32;
921 
922     /**
923      * If the media contains EXIF data, this key retrieves the offset value
924      * of the data.
925      */
926     public static final int METADATA_KEY_EXIF_OFFSET = 33;
927 
928     /**
929      * If the media contains EXIF data, this key retrieves the length of the
930      * data.
931      */
932     public static final int METADATA_KEY_EXIF_LENGTH = 34;
933 
934     /**
935      * This key retrieves the color standard, if available.
936      *
937      * @see MediaFormat#COLOR_STANDARD_BT709
938      * @see MediaFormat#COLOR_STANDARD_BT601_PAL
939      * @see MediaFormat#COLOR_STANDARD_BT601_NTSC
940      * @see MediaFormat#COLOR_STANDARD_BT2020
941      *
942      * @hide
943      */
944     public static final int METADATA_KEY_COLOR_STANDARD = 35;
945 
946     /**
947      * This key retrieves the color transfer, if available.
948      *
949      * @see MediaFormat#COLOR_TRANSFER_LINEAR
950      * @see MediaFormat#COLOR_TRANSFER_SDR_VIDEO
951      * @see MediaFormat#COLOR_TRANSFER_ST2084
952      * @see MediaFormat#COLOR_TRANSFER_HLG
953      *
954      * @hide
955      */
956     public static final int METADATA_KEY_COLOR_TRANSFER = 36;
957 
958     /**
959      * This key retrieves the color range, if available.
960      *
961      * @see MediaFormat#COLOR_RANGE_LIMITED
962      * @see MediaFormat#COLOR_RANGE_FULL
963      *
964      * @hide
965      */
966     public static final int METADATA_KEY_COLOR_RANGE    = 37;
967     // Add more here...
968 
969     /**
970      * This key retrieves the sample rate, if available.
971      * @hide
972      */
973     public static final int METADATA_KEY_SAMPLERATE      = 38;
974 
975     /**
976      * This key retrieves the bits per sample, if available.
977      * @hide
978      */
979     public static final int METADATA_KEY_BITS_PER_SAMPLE = 39;
980 }
981