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