MediaMetadataRetriever.java revision 77c500c9a1f763b31fb5a03c803b3523fcb72310
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
17package android.media;
18
19import android.content.ContentResolver;
20import android.content.Context;
21import android.content.res.AssetFileDescriptor;
22import android.graphics.Bitmap;
23import android.net.Uri;
24
25import java.io.FileDescriptor;
26import java.io.FileNotFoundException;
27import java.io.IOException;
28
29import java.util.Map;
30
31/**
32 * MediaMetadataRetriever class provides a unified interface for retrieving
33 * frame and meta data from an input media file.
34 */
35public class MediaMetadataRetriever
36{
37    static {
38        System.loadLibrary("media_jni");
39        native_init();
40    }
41
42    // The field below is accessed by native methods
43    @SuppressWarnings("unused")
44    private int mNativeContext;
45
46    private static final int EMBEDDED_PICTURE_TYPE_ANY = 0xFFFF;
47
48    public MediaMetadataRetriever() {
49        native_setup();
50    }
51
52    /**
53     * Sets the data source (file pathname) to use. Call this
54     * method before the rest of the methods in this class. This method may be
55     * time-consuming.
56     *
57     * @param path The path of the input media file.
58     * @throws IllegalArgumentException If the path is invalid.
59     */
60    public native void setDataSource(String path) throws IllegalArgumentException;
61
62    /**
63     * Sets the data source (URI) to use. Call this
64     * method before the rest of the methods in this class. This method may be
65     * time-consuming.
66     *
67     * @param uri The URI of the input media.
68     * @param headers the headers to be sent together with the request for the data
69     * @throws IllegalArgumentException If the URI is invalid.
70     */
71    public void setDataSource(String uri,  Map<String, String> headers)
72            throws IllegalArgumentException {
73        int i = 0;
74        String[] keys = new String[headers.size()];
75        String[] values = new String[headers.size()];
76        for (Map.Entry<String, String> entry: headers.entrySet()) {
77            keys[i] = entry.getKey();
78            values[i] = entry.getValue();
79            ++i;
80        }
81        _setDataSource(uri, keys, values);
82    }
83
84    private native void _setDataSource(
85        String uri, String[] keys, String[] values)
86        throws IllegalArgumentException;
87
88    /**
89     * Sets the data source (FileDescriptor) to use.  It is the caller's
90     * responsibility to close the file descriptor. It is safe to do so as soon
91     * as this call returns. Call this method before the rest of the methods in
92     * this class. This method may be time-consuming.
93     *
94     * @param fd the FileDescriptor for the file you want to play
95     * @param offset the offset into the file where the data to be played starts,
96     * in bytes. It must be non-negative
97     * @param length the length in bytes of the data to be played. It must be
98     * non-negative.
99     * @throws IllegalArgumentException if the arguments are invalid
100     */
101    public native void setDataSource(FileDescriptor fd, long offset, long length)
102            throws IllegalArgumentException;
103
104    /**
105     * Sets the data source (FileDescriptor) to use. It is the caller's
106     * responsibility to close the file descriptor. It is safe to do so as soon
107     * as this call returns. Call this method before the rest of the methods in
108     * this class. This method may be time-consuming.
109     *
110     * @param fd the FileDescriptor for the file you want to play
111     * @throws IllegalArgumentException if the FileDescriptor is invalid
112     */
113    public void setDataSource(FileDescriptor fd)
114            throws IllegalArgumentException {
115        // intentionally less than LONG_MAX
116        setDataSource(fd, 0, 0x7ffffffffffffffL);
117    }
118
119    /**
120     * Sets the data source as a content Uri. Call this method before
121     * the rest of the methods in this class. This method may be time-consuming.
122     *
123     * @param context the Context to use when resolving the Uri
124     * @param uri the Content URI of the data you want to play
125     * @throws IllegalArgumentException if the Uri is invalid
126     * @throws SecurityException if the Uri cannot be used due to lack of
127     * permission.
128     */
129    public void setDataSource(Context context, Uri uri)
130        throws IllegalArgumentException, SecurityException {
131        if (uri == null) {
132            throw new IllegalArgumentException();
133        }
134
135        String scheme = uri.getScheme();
136        if(scheme == null || scheme.equals("file")) {
137            setDataSource(uri.getPath());
138            return;
139        }
140
141        AssetFileDescriptor fd = null;
142        try {
143            ContentResolver resolver = context.getContentResolver();
144            try {
145                fd = resolver.openAssetFileDescriptor(uri, "r");
146            } catch(FileNotFoundException e) {
147                throw new IllegalArgumentException();
148            }
149            if (fd == null) {
150                throw new IllegalArgumentException();
151            }
152            FileDescriptor descriptor = fd.getFileDescriptor();
153            if (!descriptor.valid()) {
154                throw new IllegalArgumentException();
155            }
156            // Note: using getDeclaredLength so that our behavior is the same
157            // as previous versions when the content provider is returning
158            // a full file.
159            if (fd.getDeclaredLength() < 0) {
160                setDataSource(descriptor);
161            } else {
162                setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength());
163            }
164            return;
165        } catch (SecurityException ex) {
166        } finally {
167            try {
168                if (fd != null) {
169                    fd.close();
170                }
171            } catch(IOException ioEx) {
172            }
173        }
174        setDataSource(uri.toString());
175    }
176
177    /**
178     * Call this method after setDataSource(). This method retrieves the
179     * meta data value associated with the keyCode.
180     *
181     * The keyCode currently supported is listed below as METADATA_XXX
182     * constants. With any other value, it returns a null pointer.
183     *
184     * @param keyCode One of the constants listed below at the end of the class.
185     * @return The meta data value associate with the given keyCode on success;
186     * null on failure.
187     */
188    public native String extractMetadata(int keyCode);
189
190    /**
191     * Call this method after setDataSource(). This method finds a
192     * representative frame close to the given time position by considering
193     * the given option if possible, and returns it as a bitmap. This is
194     * useful for generating a thumbnail for an input data source or just
195     * obtain and display a frame at the given time position.
196     *
197     * @param timeUs The time position where the frame will be retrieved.
198     * When retrieving the frame at the given time position, there is no
199     * guarantee that the data source has a frame located at the position.
200     * When this happens, a frame nearby will be returned. If timeUs is
201     * negative, time position and option will ignored, and any frame
202     * that the implementation considers as representative may be returned.
203     *
204     * @param option a hint on how the frame is found. Use
205     * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame
206     * that has a timestamp earlier than or the same as timeUs. Use
207     * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame
208     * that has a timestamp later than or the same as timeUs. Use
209     * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame
210     * that has a timestamp closest to or the same as timeUs. Use
211     * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may
212     * or may not be a sync frame but is closest to or the same as timeUs.
213     * {@link #OPTION_CLOSEST} often has larger performance overhead compared
214     * to the other options if there is no sync frame located at timeUs.
215     *
216     * @return A Bitmap containing a representative video frame, which
217     *         can be null, if such a frame cannot be retrieved.
218     */
219    public Bitmap getFrameAtTime(long timeUs, int option) {
220        if (option < OPTION_PREVIOUS_SYNC ||
221            option > OPTION_CLOSEST) {
222            throw new IllegalArgumentException("Unsupported option: " + option);
223        }
224
225        return _getFrameAtTime(timeUs, option);
226    }
227
228    /**
229     * Call this method after setDataSource(). This method finds a
230     * representative frame close to the given time position if possible,
231     * and returns it as a bitmap. This is useful for generating a thumbnail
232     * for an input data source. Call this method if one does not care
233     * how the frame is found as long as it is close to the given time;
234     * otherwise, please call {@link #getFrameAtTime(long, int)}.
235     *
236     * @param timeUs The time position where the frame will be retrieved.
237     * When retrieving the frame at the given time position, there is no
238     * guarentee that the data source has a frame located at the position.
239     * When this happens, a frame nearby will be returned. If timeUs is
240     * negative, time position and option will ignored, and any frame
241     * that the implementation considers as representative may be returned.
242     *
243     * @return A Bitmap containing a representative video frame, which
244     *         can be null, if such a frame cannot be retrieved.
245     *
246     * @see #getFrameAtTime(long, int)
247     */
248    public Bitmap getFrameAtTime(long timeUs) {
249        return getFrameAtTime(timeUs, OPTION_CLOSEST_SYNC);
250    }
251
252    /**
253     * Call this method after setDataSource(). This method finds a
254     * representative frame at any time position if possible,
255     * and returns it as a bitmap. This is useful for generating a thumbnail
256     * for an input data source. Call this method if one does not
257     * care about where the frame is located; otherwise, please call
258     * {@link #getFrameAtTime(long)} or {@link #getFrameAtTime(long, int)}
259     *
260     * @return A Bitmap containing a representative video frame, which
261     *         can be null, if such a frame cannot be retrieved.
262     *
263     * @see #getFrameAtTime(long)
264     * @see #getFrameAtTime(long, int)
265     */
266    public Bitmap getFrameAtTime() {
267        return getFrameAtTime(-1, OPTION_CLOSEST_SYNC);
268    }
269
270    private native Bitmap _getFrameAtTime(long timeUs, int option);
271
272
273    /**
274     * Call this method after setDataSource(). This method finds the optional
275     * graphic or album/cover art associated associated with the data source. If
276     * there are more than one pictures, (any) one of them is returned.
277     *
278     * @return null if no such graphic is found.
279     */
280    public byte[] getEmbeddedPicture() {
281        return getEmbeddedPicture(EMBEDDED_PICTURE_TYPE_ANY);
282    }
283
284    private native byte[] getEmbeddedPicture(int pictureType);
285
286    /**
287     * Call it when one is done with the object. This method releases the memory
288     * allocated internally.
289     */
290    public native void release();
291    private native void native_setup();
292    private static native void native_init();
293
294    private native final void native_finalize();
295
296    @Override
297    protected void finalize() throws Throwable {
298        try {
299            native_finalize();
300        } finally {
301            super.finalize();
302        }
303    }
304
305    /**
306     * Option used in method {@link #getFrameAtTime(long, int)} to get a
307     * frame at a specified location.
308     *
309     * @see #getFrameAtTime(long, int)
310     */
311    /* Do not change these option values without updating their counterparts
312     * in include/media/stagefright/MediaSource.h!
313     */
314    /**
315     * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
316     * a sync (or key) frame associated with a data source that is located
317     * right before or at the given time.
318     *
319     * @see #getFrameAtTime(long, int)
320     */
321    public static final int OPTION_PREVIOUS_SYNC    = 0x00;
322    /**
323     * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
324     * a sync (or key) frame associated with a data source that is located
325     * right after or at the given time.
326     *
327     * @see #getFrameAtTime(long, int)
328     */
329    public static final int OPTION_NEXT_SYNC        = 0x01;
330    /**
331     * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
332     * a sync (or key) frame associated with a data source that is located
333     * closest to (in time) or at the given time.
334     *
335     * @see #getFrameAtTime(long, int)
336     */
337    public static final int OPTION_CLOSEST_SYNC     = 0x02;
338    /**
339     * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
340     * a frame (not necessarily a key frame) associated with a data source that
341     * is located closest to or at the given time.
342     *
343     * @see #getFrameAtTime(long, int)
344     */
345    public static final int OPTION_CLOSEST          = 0x03;
346
347    /*
348     * Do not change these metadata key values without updating their
349     * counterparts in include/media/mediametadataretriever.h!
350     */
351    /**
352     * The metadata key to retrieve the numberic string describing the
353     * order of the audio data source on its original recording.
354     */
355    public static final int METADATA_KEY_CD_TRACK_NUMBER = 0;
356    /**
357     * The metadata key to retrieve the information about the album title
358     * of the data source.
359     */
360    public static final int METADATA_KEY_ALBUM           = 1;
361    /**
362     * The metadata key to retrieve the information about the artist of
363     * the data source.
364     */
365    public static final int METADATA_KEY_ARTIST          = 2;
366    /**
367     * The metadata key to retrieve the information about the author of
368     * the data source.
369     */
370    public static final int METADATA_KEY_AUTHOR          = 3;
371    /**
372     * The metadata key to retrieve the information about the composer of
373     * the data source.
374     */
375    public static final int METADATA_KEY_COMPOSER        = 4;
376    /**
377     * The metadata key to retrieve the date when the data source was created
378     * or modified.
379     */
380    public static final int METADATA_KEY_DATE            = 5;
381    /**
382     * The metadata key to retrieve the content type or genre of the data
383     * source.
384     */
385    public static final int METADATA_KEY_GENRE           = 6;
386    /**
387     * The metadata key to retrieve the data source title.
388     */
389    public static final int METADATA_KEY_TITLE           = 7;
390    /**
391     * The metadata key to retrieve the year when the data source was created
392     * or modified.
393     */
394    public static final int METADATA_KEY_YEAR            = 8;
395    /**
396     * The metadata key to retrieve the playback duration of the data source.
397     */
398    public static final int METADATA_KEY_DURATION        = 9;
399    /**
400     * The metadata key to retrieve the number of tracks, such as audio, video,
401     * text, in the data source, such as a mp4 or 3gpp file.
402     */
403    public static final int METADATA_KEY_NUM_TRACKS      = 10;
404    /**
405     * The metadata key to retrieve the information of the writer (such as
406     * lyricist) of the data source.
407     */
408    public static final int METADATA_KEY_WRITER          = 11;
409    /**
410     * The metadata key to retrieve the mime type of the data source. Some
411     * example mime types include: "video/mp4", "audio/mp4", "audio/amr-wb",
412     * etc.
413     */
414    public static final int METADATA_KEY_MIMETYPE        = 12;
415    /**
416     * The metadata key to retrieve the information about the performers or
417     * artist associated with the data source.
418     */
419    public static final int METADATA_KEY_ALBUMARTIST     = 13;
420    /**
421     * The metadata key to retrieve the numberic string that describes which
422     * part of a set the audio data source comes from.
423     */
424    public static final int METADATA_KEY_DISC_NUMBER     = 14;
425    /**
426     * The metadata key to retrieve the music album compilation status.
427     */
428    public static final int METADATA_KEY_COMPILATION     = 15;
429    /**
430     * If this key exists the media contains audio content.
431     */
432    public static final int METADATA_KEY_HAS_AUDIO       = 16;
433    /**
434     * If this key exists the media contains video content.
435     */
436    public static final int METADATA_KEY_HAS_VIDEO       = 17;
437    /**
438     * If the media contains video, this key retrieves its width.
439     */
440    public static final int METADATA_KEY_VIDEO_WIDTH     = 18;
441    /**
442     * If the media contains video, this key retrieves its height.
443     */
444    public static final int METADATA_KEY_VIDEO_HEIGHT    = 19;
445    /**
446     * This key retrieves the average bitrate (in bits/sec), if available.
447     */
448    public static final int METADATA_KEY_BITRATE         = 20;
449    /**
450     * This key retrieves the language code of text tracks, if available.
451     * If multiple text tracks present, the return value will look like:
452     * "eng:chi"
453     * @hide
454     */
455    public static final int METADATA_KEY_TIMED_TEXT_LANGUAGES      = 21;
456    /**
457     * If this key exists the media is drm-protected.
458     * @hide
459     */
460    public static final int METADATA_KEY_IS_DRM          = 22;
461    /**
462     * This key retrieves the location information, if available.
463     * The location should be specified according to ISO-6709 standard, under
464     * a mp4/3gp box "@xyz". Location with longitude of -90 degrees and latitude
465     * of 180 degrees will be retrieved as "-90.0000+180.0000", for instance.
466     * @hide
467     */
468    public static final int METADATA_KEY_LOCATION        = 23;
469    // Add more here...
470}
471