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