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