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