Home | History | Annotate | Download | only in media
      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");
     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 
     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      */
     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      */
     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 
    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      */
    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      */
    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      */
    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      */
    207     public void setDataSource(MediaDataSource dataSource)
    208             throws IllegalArgumentException {
    209         _setDataSource(dataSource);
    210     }
    211 
    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      */
    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      */
    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      */
    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      */
    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      */
    366     public Bitmap getFrameAtTime() {
    367         return _getFrameAtTime(-1, OPTION_CLOSEST_SYNC, -1 /*dst_width*/, -1 /*dst_height*/);
    368     }
    369 
    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          */
    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          */
    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          */
    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          */
    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      */
    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      */
    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      */
    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      */
    522     public @NonNull List<Bitmap> getFramesAtIndex(int frameIndex, int numFrames) {
    523         return getFramesAtIndexInternal(frameIndex, numFrames, null);
    524     }
    525 
    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 
    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      */
    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      */
    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      */
    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      */
    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      */
    641     public Bitmap getPrimaryImage() {
    642         return getImageAtIndexInternal(-1, null);
    643     }
    644 
    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 
    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      */
    667     public byte[] getEmbeddedPicture() {
    668         return getEmbeddedPicture(EMBEDDED_PICTURE_TYPE_ANY);
    669     }
    670 
    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      */
    677     public native void release();
    678     private native void native_setup();
    679     private static native void native_init();
    680 
    681     private native final void native_finalize();
    682 
    683     @Override
    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