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