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