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