MediaMetadataRetriever.java revision 17524dc0d296146c8ffb3f692dc8ab05fee5b1e0
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 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 // Add more here... 457} 458