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.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.content.ContentResolver; 23 import android.content.Context; 24 import android.content.res.AssetFileDescriptor; 25 import android.graphics.Bitmap; 26 import android.net.Uri; 27 import android.os.IBinder; 28 29 import java.io.FileDescriptor; 30 import java.io.FileInputStream; 31 import java.io.FileNotFoundException; 32 import java.io.IOException; 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 35 import java.util.List; 36 import java.util.Map; 37 38 /** 39 * MediaMetadataRetriever class provides a unified interface for retrieving 40 * frame and meta data from an input media file. 41 */ 42 public class MediaMetadataRetriever 43 { 44 static { 45 System.loadLibrary("media_jni"); native_init()46 native_init(); 47 } 48 49 // The field below is accessed by native methods 50 @SuppressWarnings("unused") 51 private long mNativeContext; 52 53 private static final int EMBEDDED_PICTURE_TYPE_ANY = 0xFFFF; 54 MediaMetadataRetriever()55 public MediaMetadataRetriever() { 56 native_setup(); 57 } 58 59 /** 60 * Sets the data source (file pathname) to use. Call this 61 * method before the rest of the methods in this class. This method may be 62 * time-consuming. 63 * 64 * @param path The path of the input media file. 65 * @throws IllegalArgumentException If the path is invalid. 66 */ setDataSource(String path)67 public void setDataSource(String path) throws IllegalArgumentException { 68 if (path == null) { 69 throw new IllegalArgumentException(); 70 } 71 72 try (FileInputStream is = new FileInputStream(path)) { 73 FileDescriptor fd = is.getFD(); 74 setDataSource(fd, 0, 0x7ffffffffffffffL); 75 } catch (FileNotFoundException fileEx) { 76 throw new IllegalArgumentException(); 77 } catch (IOException ioEx) { 78 throw new IllegalArgumentException(); 79 } 80 } 81 82 /** 83 * Sets the data source (URI) to use. Call this 84 * method before the rest of the methods in this class. This method may be 85 * time-consuming. 86 * 87 * @param uri The URI of the input media. 88 * @param headers the headers to be sent together with the request for the data 89 * @throws IllegalArgumentException If the URI is invalid. 90 */ setDataSource(String uri, Map<String, String> headers)91 public void setDataSource(String uri, Map<String, String> headers) 92 throws IllegalArgumentException { 93 int i = 0; 94 String[] keys = new String[headers.size()]; 95 String[] values = new String[headers.size()]; 96 for (Map.Entry<String, String> entry: headers.entrySet()) { 97 keys[i] = entry.getKey(); 98 values[i] = entry.getValue(); 99 ++i; 100 } 101 102 _setDataSource( 103 MediaHTTPService.createHttpServiceBinderIfNecessary(uri), 104 uri, 105 keys, 106 values); 107 } 108 _setDataSource( IBinder httpServiceBinder, String uri, String[] keys, String[] values)109 private native void _setDataSource( 110 IBinder httpServiceBinder, String uri, String[] keys, String[] values) 111 throws IllegalArgumentException; 112 113 /** 114 * Sets the data source (FileDescriptor) to use. It is the caller's 115 * responsibility to close the file descriptor. It is safe to do so as soon 116 * as this call returns. Call this method before the rest of the methods in 117 * this class. This method may be time-consuming. 118 * 119 * @param fd the FileDescriptor for the file you want to play 120 * @param offset the offset into the file where the data to be played starts, 121 * in bytes. It must be non-negative 122 * @param length the length in bytes of the data to be played. It must be 123 * non-negative. 124 * @throws IllegalArgumentException if the arguments are invalid 125 */ setDataSource(FileDescriptor fd, long offset, long length)126 public native void setDataSource(FileDescriptor fd, long offset, long length) 127 throws IllegalArgumentException; 128 129 /** 130 * Sets the data source (FileDescriptor) to use. It is the caller's 131 * responsibility to close the file descriptor. It is safe to do so as soon 132 * as this call returns. Call this method before the rest of the methods in 133 * this class. This method may be time-consuming. 134 * 135 * @param fd the FileDescriptor for the file you want to play 136 * @throws IllegalArgumentException if the FileDescriptor is invalid 137 */ setDataSource(FileDescriptor fd)138 public void setDataSource(FileDescriptor fd) 139 throws IllegalArgumentException { 140 // intentionally less than LONG_MAX 141 setDataSource(fd, 0, 0x7ffffffffffffffL); 142 } 143 144 /** 145 * Sets the data source as a content Uri. Call this method before 146 * the rest of the methods in this class. This method may be time-consuming. 147 * 148 * @param context the Context to use when resolving the Uri 149 * @param uri the Content URI of the data you want to play 150 * @throws IllegalArgumentException if the Uri is invalid 151 * @throws SecurityException if the Uri cannot be used due to lack of 152 * permission. 153 */ setDataSource(Context context, Uri uri)154 public void setDataSource(Context context, Uri uri) 155 throws IllegalArgumentException, SecurityException { 156 if (uri == null) { 157 throw new IllegalArgumentException(); 158 } 159 160 String scheme = uri.getScheme(); 161 if(scheme == null || scheme.equals("file")) { 162 setDataSource(uri.getPath()); 163 return; 164 } 165 166 AssetFileDescriptor fd = null; 167 try { 168 ContentResolver resolver = context.getContentResolver(); 169 try { 170 fd = resolver.openAssetFileDescriptor(uri, "r"); 171 } catch(FileNotFoundException e) { 172 throw new IllegalArgumentException(); 173 } 174 if (fd == null) { 175 throw new IllegalArgumentException(); 176 } 177 FileDescriptor descriptor = fd.getFileDescriptor(); 178 if (!descriptor.valid()) { 179 throw new IllegalArgumentException(); 180 } 181 // Note: using getDeclaredLength so that our behavior is the same 182 // as previous versions when the content provider is returning 183 // a full file. 184 if (fd.getDeclaredLength() < 0) { 185 setDataSource(descriptor); 186 } else { 187 setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength()); 188 } 189 return; 190 } catch (SecurityException ex) { 191 } finally { 192 try { 193 if (fd != null) { 194 fd.close(); 195 } 196 } catch(IOException ioEx) { 197 } 198 } 199 setDataSource(uri.toString()); 200 } 201 202 /** 203 * Sets the data source (MediaDataSource) to use. 204 * 205 * @param dataSource the MediaDataSource for the media you want to play 206 */ setDataSource(MediaDataSource dataSource)207 public void setDataSource(MediaDataSource dataSource) 208 throws IllegalArgumentException { 209 _setDataSource(dataSource); 210 } 211 _setDataSource(MediaDataSource dataSource)212 private native void _setDataSource(MediaDataSource dataSource) 213 throws IllegalArgumentException; 214 215 /** 216 * Call this method after setDataSource(). This method retrieves the 217 * meta data value associated with the keyCode. 218 * 219 * The keyCode currently supported is listed below as METADATA_XXX 220 * constants. With any other value, it returns a null pointer. 221 * 222 * @param keyCode One of the constants listed below at the end of the class. 223 * @return The meta data value associate with the given keyCode on success; 224 * null on failure. 225 */ extractMetadata(int keyCode)226 public native String extractMetadata(int keyCode); 227 228 /** 229 * Call this method after setDataSource(). This method finds a 230 * representative frame close to the given time position by considering 231 * the given option if possible, and returns it as a bitmap. 232 * 233 * <p>If you don't need a full-resolution 234 * frame (for example, because you need a thumbnail image), use 235 * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this 236 * method.</p> 237 * 238 * @param timeUs The time position where the frame will be retrieved. 239 * When retrieving the frame at the given time position, there is no 240 * guarantee that the data source has a frame located at the position. 241 * When this happens, a frame nearby will be returned. If timeUs is 242 * negative, time position and option will ignored, and any frame 243 * that the implementation considers as representative may be returned. 244 * 245 * @param option a hint on how the frame is found. Use 246 * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame 247 * that has a timestamp earlier than or the same as timeUs. Use 248 * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame 249 * that has a timestamp later than or the same as timeUs. Use 250 * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame 251 * that has a timestamp closest to or the same as timeUs. Use 252 * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may 253 * or may not be a sync frame but is closest to or the same as timeUs. 254 * {@link #OPTION_CLOSEST} often has larger performance overhead compared 255 * to the other options if there is no sync frame located at timeUs. 256 * 257 * @return A Bitmap containing a representative video frame, which 258 * can be null, if such a frame cannot be retrieved. 259 */ getFrameAtTime(long timeUs, @Option int option)260 public Bitmap getFrameAtTime(long timeUs, @Option int option) { 261 if (option < OPTION_PREVIOUS_SYNC || 262 option > OPTION_CLOSEST) { 263 throw new IllegalArgumentException("Unsupported option: " + option); 264 } 265 266 return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/); 267 } 268 269 /** 270 * Retrieve a video frame near a given timestamp scaled to a desired size. 271 * Call this method after setDataSource(). This method finds a representative 272 * frame close to the given time position by considering the given option 273 * if possible, and returns it as a bitmap with same aspect ratio as the source 274 * while scaling it so that it fits into the desired size of dst_width by dst_height. 275 * This is useful for generating a thumbnail for an input data source or just to 276 * obtain a scaled frame at the given time position. 277 * 278 * @param timeUs The time position in microseconds where the frame will be retrieved. 279 * When retrieving the frame at the given time position, there is no 280 * guarantee that the data source has a frame located at the position. 281 * When this happens, a frame nearby will be returned. If timeUs is 282 * negative, time position and option will ignored, and any frame 283 * that the implementation considers as representative may be returned. 284 * 285 * @param option a hint on how the frame is found. Use 286 * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame 287 * that has a timestamp earlier than or the same as timeUs. Use 288 * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame 289 * that has a timestamp later than or the same as timeUs. Use 290 * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame 291 * that has a timestamp closest to or the same as timeUs. Use 292 * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may 293 * or may not be a sync frame but is closest to or the same as timeUs. 294 * {@link #OPTION_CLOSEST} often has larger performance overhead compared 295 * to the other options if there is no sync frame located at timeUs. 296 * 297 * @param dstWidth expected output bitmap width 298 * @param dstHeight expected output bitmap height 299 * @return A Bitmap of size not larger than dstWidth by dstHeight containing a 300 * scaled video frame, which can be null, if such a frame cannot be retrieved. 301 * @throws IllegalArgumentException if passed in invalid option or width by height 302 * is less than or equal to 0. 303 */ getScaledFrameAtTime( long timeUs, @Option int option, int dstWidth, int dstHeight)304 public Bitmap getScaledFrameAtTime( 305 long timeUs, @Option int option, int dstWidth, int dstHeight) { 306 if (option < OPTION_PREVIOUS_SYNC || 307 option > OPTION_CLOSEST) { 308 throw new IllegalArgumentException("Unsupported option: " + option); 309 } 310 if (dstWidth <= 0) { 311 throw new IllegalArgumentException("Invalid width: " + dstWidth); 312 } 313 if (dstHeight <= 0) { 314 throw new IllegalArgumentException("Invalid height: " + dstHeight); 315 } 316 317 return _getFrameAtTime(timeUs, option, dstWidth, dstHeight); 318 } 319 320 /** 321 * Call this method after setDataSource(). This method finds a 322 * representative frame close to the given time position if possible, 323 * and returns it as a bitmap. Call this method if one does not care 324 * how the frame is found as long as it is close to the given time; 325 * otherwise, please call {@link #getFrameAtTime(long, int)}. 326 * 327 * <p>If you don't need a full-resolution 328 * frame (for example, because you need a thumbnail image), use 329 * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this 330 * method.</p> 331 * 332 * @param timeUs The time position where the frame will be retrieved. 333 * When retrieving the frame at the given time position, there is no 334 * guarentee that the data source has a frame located at the position. 335 * When this happens, a frame nearby will be returned. If timeUs is 336 * negative, time position and option will ignored, and any frame 337 * that the implementation considers as representative may be returned. 338 * 339 * @return A Bitmap of size dst_widthxdst_height containing a representative 340 * video frame, which can be null, if such a frame cannot be retrieved. 341 * 342 * @see #getFrameAtTime(long, int) 343 */ getFrameAtTime(long timeUs)344 public Bitmap getFrameAtTime(long timeUs) { 345 return getFrameAtTime(timeUs, OPTION_CLOSEST_SYNC); 346 } 347 348 /** 349 * Call this method after setDataSource(). This method finds a 350 * representative frame at any time position if possible, 351 * and returns it as a bitmap. Call this method if one does not 352 * care about where the frame is located; otherwise, please call 353 * {@link #getFrameAtTime(long)} or {@link #getFrameAtTime(long, int)} 354 * 355 * <p>If you don't need a full-resolution 356 * frame (for example, because you need a thumbnail image), use 357 * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this 358 * method.</p> 359 * 360 * @return A Bitmap containing a representative video frame, which 361 * can be null, if such a frame cannot be retrieved. 362 * 363 * @see #getFrameAtTime(long) 364 * @see #getFrameAtTime(long, int) 365 */ getFrameAtTime()366 public Bitmap getFrameAtTime() { 367 return _getFrameAtTime(-1, OPTION_CLOSEST_SYNC, -1 /*dst_width*/, -1 /*dst_height*/); 368 } 369 _getFrameAtTime(long timeUs, int option, int width, int height)370 private native Bitmap _getFrameAtTime(long timeUs, int option, int width, int height); 371 372 public static final class BitmapParams { 373 private Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888; 374 private Bitmap.Config outActualConfig = Bitmap.Config.ARGB_8888; 375 376 /** 377 * Create a default BitmapParams object. By default, it uses {@link Bitmap.Config#ARGB_8888} 378 * as the preferred bitmap config. 379 */ BitmapParams()380 public BitmapParams() {} 381 382 /** 383 * Set the preferred bitmap config for the decoder to decode into. 384 * 385 * If not set, or the request cannot be met, the decoder will output 386 * in {@link Bitmap.Config#ARGB_8888} config by default. 387 * 388 * After decode, the actual config used can be retrieved by {@link #getActualConfig()}. 389 * 390 * @param config the preferred bitmap config to use. 391 */ setPreferredConfig(@onNull Bitmap.Config config)392 public void setPreferredConfig(@NonNull Bitmap.Config config) { 393 if (config == null) { 394 throw new IllegalArgumentException("preferred config can't be null"); 395 } 396 inPreferredConfig = config; 397 } 398 399 /** 400 * Retrieve the preferred bitmap config in the params. 401 * 402 * @return the preferred bitmap config. 403 */ getPreferredConfig()404 public @NonNull Bitmap.Config getPreferredConfig() { 405 return inPreferredConfig; 406 } 407 408 /** 409 * Get the actual bitmap config used to decode the bitmap after the decoding. 410 * 411 * @return the actual bitmap config used. 412 */ getActualConfig()413 public @NonNull Bitmap.Config getActualConfig() { 414 return outActualConfig; 415 } 416 } 417 418 /** 419 * This method retrieves a video frame by its index. It should only be called 420 * after {@link #setDataSource}. 421 * 422 * After the bitmap is returned, you can query the actual parameters that were 423 * used to create the bitmap from the {@code BitmapParams} argument, for instance 424 * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}. 425 * 426 * @param frameIndex 0-based index of the video frame. The frame index must be that of 427 * a valid frame. The total number of frames available for retrieval can be queried 428 * via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key. 429 * @param params BitmapParams that controls the returned bitmap config (such as pixel formats). 430 * 431 * @throws IllegalStateException if the container doesn't contain video or image sequences. 432 * @throws IllegalArgumentException if the requested frame index does not exist. 433 * 434 * @return A Bitmap containing the requested video frame, or null if the retrieval fails. 435 * 436 * @see #getFrameAtIndex(int) 437 * @see #getFramesAtIndex(int, int, BitmapParams) 438 * @see #getFramesAtIndex(int, int) 439 */ getFrameAtIndex(int frameIndex, @NonNull BitmapParams params)440 public Bitmap getFrameAtIndex(int frameIndex, @NonNull BitmapParams params) { 441 List<Bitmap> bitmaps = getFramesAtIndex(frameIndex, 1, params); 442 return bitmaps.get(0); 443 } 444 445 /** 446 * This method is similar to {@link #getFrameAtIndex(int, BitmapParams)} except that 447 * the default for {@link BitmapParams} will be used. 448 * 449 * @param frameIndex 0-based index of the video frame. The frame index must be that of 450 * a valid frame. The total number of frames available for retrieval can be queried 451 * via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key. 452 * 453 * @throws IllegalStateException if the container doesn't contain video or image sequences. 454 * @throws IllegalArgumentException if the requested frame index does not exist. 455 * 456 * @return A Bitmap containing the requested video frame, or null if the retrieval fails. 457 * 458 * @see #getFrameAtIndex(int, BitmapParams) 459 * @see #getFramesAtIndex(int, int, BitmapParams) 460 * @see #getFramesAtIndex(int, int) 461 */ getFrameAtIndex(int frameIndex)462 public Bitmap getFrameAtIndex(int frameIndex) { 463 List<Bitmap> bitmaps = getFramesAtIndex(frameIndex, 1); 464 return bitmaps.get(0); 465 } 466 467 /** 468 * This method retrieves a consecutive set of video frames starting at the 469 * specified index. It should only be called after {@link #setDataSource}. 470 * 471 * If the caller intends to retrieve more than one consecutive video frames, 472 * this method is preferred over {@link #getFrameAtIndex(int, BitmapParams)} for efficiency. 473 * 474 * After the bitmaps are returned, you can query the actual parameters that were 475 * used to create the bitmaps from the {@code BitmapParams} argument, for instance 476 * to query the bitmap config used for the bitmaps with {@link BitmapParams#getActualConfig}. 477 * 478 * @param frameIndex 0-based index of the first video frame to retrieve. The frame index 479 * must be that of a valid frame. The total number of frames available for retrieval 480 * can be queried via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key. 481 * @param numFrames number of consecutive video frames to retrieve. Must be a positive 482 * value. The stream must contain at least numFrames frames starting at frameIndex. 483 * @param params BitmapParams that controls the returned bitmap config (such as pixel formats). 484 * 485 * @throws IllegalStateException if the container doesn't contain video or image sequences. 486 * @throws IllegalArgumentException if the frameIndex or numFrames is invalid, or the 487 * stream doesn't contain at least numFrames starting at frameIndex. 488 489 * @return An list of Bitmaps containing the requested video frames. The returned 490 * array could contain less frames than requested if the retrieval fails. 491 * 492 * @see #getFrameAtIndex(int, BitmapParams) 493 * @see #getFrameAtIndex(int) 494 * @see #getFramesAtIndex(int, int) 495 */ getFramesAtIndex( int frameIndex, int numFrames, @NonNull BitmapParams params)496 public @NonNull List<Bitmap> getFramesAtIndex( 497 int frameIndex, int numFrames, @NonNull BitmapParams params) { 498 return getFramesAtIndexInternal(frameIndex, numFrames, params); 499 } 500 501 /** 502 * This method is similar to {@link #getFramesAtIndex(int, int, BitmapParams)} except that 503 * the default for {@link BitmapParams} will be used. 504 * 505 * @param frameIndex 0-based index of the first video frame to retrieve. The frame index 506 * must be that of a valid frame. The total number of frames available for retrieval 507 * can be queried via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key. 508 * @param numFrames number of consecutive video frames to retrieve. Must be a positive 509 * value. The stream must contain at least numFrames frames starting at frameIndex. 510 * 511 * @throws IllegalStateException if the container doesn't contain video or image sequences. 512 * @throws IllegalArgumentException if the frameIndex or numFrames is invalid, or the 513 * stream doesn't contain at least numFrames starting at frameIndex. 514 515 * @return An list of Bitmaps containing the requested video frames. The returned 516 * array could contain less frames than requested if the retrieval fails. 517 * 518 * @see #getFrameAtIndex(int, BitmapParams) 519 * @see #getFrameAtIndex(int) 520 * @see #getFramesAtIndex(int, int, BitmapParams) 521 */ getFramesAtIndex(int frameIndex, int numFrames)522 public @NonNull List<Bitmap> getFramesAtIndex(int frameIndex, int numFrames) { 523 return getFramesAtIndexInternal(frameIndex, numFrames, null); 524 } 525 getFramesAtIndexInternal( int frameIndex, int numFrames, @Nullable BitmapParams params)526 private @NonNull List<Bitmap> getFramesAtIndexInternal( 527 int frameIndex, int numFrames, @Nullable BitmapParams params) { 528 if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO))) { 529 throw new IllegalStateException("Does not contail video or image sequences"); 530 } 531 int frameCount = Integer.parseInt( 532 extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT)); 533 if (frameIndex < 0 || numFrames < 1 534 || frameIndex >= frameCount 535 || frameIndex > frameCount - numFrames) { 536 throw new IllegalArgumentException("Invalid frameIndex or numFrames: " 537 + frameIndex + ", " + numFrames); 538 } 539 return _getFrameAtIndex(frameIndex, numFrames, params); 540 } 541 _getFrameAtIndex( int frameIndex, int numFrames, @Nullable BitmapParams params)542 private native @NonNull List<Bitmap> _getFrameAtIndex( 543 int frameIndex, int numFrames, @Nullable BitmapParams params); 544 545 /** 546 * This method retrieves a still image by its index. It should only be called 547 * after {@link #setDataSource}. 548 * 549 * After the bitmap is returned, you can query the actual parameters that were 550 * used to create the bitmap from the {@code BitmapParams} argument, for instance 551 * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}. 552 * 553 * @param imageIndex 0-based index of the image. 554 * @param params BitmapParams that controls the returned bitmap config (such as pixel formats). 555 * 556 * @throws IllegalStateException if the container doesn't contain still images. 557 * @throws IllegalArgumentException if the requested image does not exist. 558 * 559 * @return the requested still image, or null if the image cannot be retrieved. 560 * 561 * @see #getImageAtIndex(int) 562 * @see #getPrimaryImage(BitmapParams) 563 * @see #getPrimaryImage() 564 */ getImageAtIndex(int imageIndex, @NonNull BitmapParams params)565 public Bitmap getImageAtIndex(int imageIndex, @NonNull BitmapParams params) { 566 return getImageAtIndexInternal(imageIndex, params); 567 } 568 569 /** 570 * @hide 571 * 572 * This method retrieves the thumbnail image for a still image if it's available. 573 * It should only be called after {@link #setDataSource}. 574 * 575 * @param imageIndex 0-based index of the image, negative value indicates primary image. 576 * @param params BitmapParams that controls the returned bitmap config (such as pixel formats). 577 * @param targetSize intended size of one edge (wdith or height) of the thumbnail, 578 * this is a heuristic for the framework to decide whether the embedded 579 * thumbnail should be used. 580 * @param maxPixels maximum pixels of thumbnail, this is a heuristic for the frameowrk to 581 * decide whehther the embedded thumnbail (or a downscaled version of it) 582 * should be used. 583 * @return the retrieved thumbnail, or null if no suitable thumbnail is available. 584 */ getThumbnailImageAtIndex( int imageIndex, @NonNull BitmapParams params, int targetSize, int maxPixels)585 public native @Nullable Bitmap getThumbnailImageAtIndex( 586 int imageIndex, @NonNull BitmapParams params, int targetSize, int maxPixels); 587 588 /** 589 * This method is similar to {@link #getImageAtIndex(int, BitmapParams)} except that 590 * the default for {@link BitmapParams} will be used. 591 * 592 * @param imageIndex 0-based index of the image. 593 * 594 * @throws IllegalStateException if the container doesn't contain still images. 595 * @throws IllegalArgumentException if the requested image does not exist. 596 * 597 * @return the requested still image, or null if the image cannot be retrieved. 598 * 599 * @see #getImageAtIndex(int, BitmapParams) 600 * @see #getPrimaryImage(BitmapParams) 601 * @see #getPrimaryImage() 602 */ getImageAtIndex(int imageIndex)603 public Bitmap getImageAtIndex(int imageIndex) { 604 return getImageAtIndexInternal(imageIndex, null); 605 } 606 607 /** 608 * This method retrieves the primary image of the media content. It should only 609 * be called after {@link #setDataSource}. 610 * 611 * After the bitmap is returned, you can query the actual parameters that were 612 * used to create the bitmap from the {@code BitmapParams} argument, for instance 613 * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}. 614 * 615 * @param params BitmapParams that controls the returned bitmap config (such as pixel formats). 616 * 617 * @return the primary image, or null if it cannot be retrieved. 618 * 619 * @throws IllegalStateException if the container doesn't contain still images. 620 * 621 * @see #getImageAtIndex(int, BitmapParams) 622 * @see #getImageAtIndex(int) 623 * @see #getPrimaryImage() 624 */ getPrimaryImage(@onNull BitmapParams params)625 public Bitmap getPrimaryImage(@NonNull BitmapParams params) { 626 return getImageAtIndexInternal(-1, params); 627 } 628 629 /** 630 * This method is similar to {@link #getPrimaryImage(BitmapParams)} except that 631 * the default for {@link BitmapParams} will be used. 632 * 633 * @return the primary image, or null if it cannot be retrieved. 634 * 635 * @throws IllegalStateException if the container doesn't contain still images. 636 * 637 * @see #getImageAtIndex(int, BitmapParams) 638 * @see #getImageAtIndex(int) 639 * @see #getPrimaryImage(BitmapParams) 640 */ getPrimaryImage()641 public Bitmap getPrimaryImage() { 642 return getImageAtIndexInternal(-1, null); 643 } 644 getImageAtIndexInternal(int imageIndex, @Nullable BitmapParams params)645 private Bitmap getImageAtIndexInternal(int imageIndex, @Nullable BitmapParams params) { 646 if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE))) { 647 throw new IllegalStateException("Does not contail still images"); 648 } 649 650 String imageCount = extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT); 651 if (imageIndex >= Integer.parseInt(imageCount)) { 652 throw new IllegalArgumentException("Invalid image index: " + imageCount); 653 } 654 655 return _getImageAtIndex(imageIndex, params); 656 } 657 _getImageAtIndex(int imageIndex, @Nullable BitmapParams params)658 private native Bitmap _getImageAtIndex(int imageIndex, @Nullable BitmapParams params); 659 660 /** 661 * Call this method after setDataSource(). This method finds the optional 662 * graphic or album/cover art associated associated with the data source. If 663 * there are more than one pictures, (any) one of them is returned. 664 * 665 * @return null if no such graphic is found. 666 */ getEmbeddedPicture()667 public byte[] getEmbeddedPicture() { 668 return getEmbeddedPicture(EMBEDDED_PICTURE_TYPE_ANY); 669 } 670 getEmbeddedPicture(int pictureType)671 private native byte[] getEmbeddedPicture(int pictureType); 672 673 /** 674 * Call it when one is done with the object. This method releases the memory 675 * allocated internally. 676 */ release()677 public native void release(); native_setup()678 private native void native_setup(); native_init()679 private static native void native_init(); 680 native_finalize()681 private native final void native_finalize(); 682 683 @Override finalize()684 protected void finalize() throws Throwable { 685 try { 686 native_finalize(); 687 } finally { 688 super.finalize(); 689 } 690 } 691 692 /** 693 * Option used in method {@link #getFrameAtTime(long, int)} to get a 694 * frame at a specified location. 695 * 696 * @see #getFrameAtTime(long, int) 697 */ 698 /* Do not change these option values without updating their counterparts 699 * in include/media/MediaSource.h! 700 */ 701 /** 702 * This option is used with {@link #getFrameAtTime(long, int)} to retrieve 703 * a sync (or key) frame associated with a data source that is located 704 * right before or at the given time. 705 * 706 * @see #getFrameAtTime(long, int) 707 */ 708 public static final int OPTION_PREVIOUS_SYNC = 0x00; 709 /** 710 * This option is used with {@link #getFrameAtTime(long, int)} to retrieve 711 * a sync (or key) frame associated with a data source that is located 712 * right after or at the given time. 713 * 714 * @see #getFrameAtTime(long, int) 715 */ 716 public static final int OPTION_NEXT_SYNC = 0x01; 717 /** 718 * This option is used with {@link #getFrameAtTime(long, int)} to retrieve 719 * a sync (or key) frame associated with a data source that is located 720 * closest to (in time) or at the given time. 721 * 722 * @see #getFrameAtTime(long, int) 723 */ 724 public static final int OPTION_CLOSEST_SYNC = 0x02; 725 /** 726 * This option is used with {@link #getFrameAtTime(long, int)} to retrieve 727 * a frame (not necessarily a key frame) associated with a data source that 728 * is located closest to or at the given time. 729 * 730 * @see #getFrameAtTime(long, int) 731 */ 732 public static final int OPTION_CLOSEST = 0x03; 733 734 /** @hide */ 735 @IntDef(flag = true, prefix = { "OPTION_" }, value = { 736 OPTION_PREVIOUS_SYNC, 737 OPTION_NEXT_SYNC, 738 OPTION_CLOSEST_SYNC, 739 OPTION_CLOSEST, 740 }) 741 @Retention(RetentionPolicy.SOURCE) 742 public @interface Option {} 743 744 /* 745 * Do not change these metadata key values without updating their 746 * counterparts in include/media/mediametadataretriever.h! 747 */ 748 /** 749 * The metadata key to retrieve the numeric string describing the 750 * order of the audio data source on its original recording. 751 */ 752 public static final int METADATA_KEY_CD_TRACK_NUMBER = 0; 753 /** 754 * The metadata key to retrieve the information about the album title 755 * of the data source. 756 */ 757 public static final int METADATA_KEY_ALBUM = 1; 758 /** 759 * The metadata key to retrieve the information about the artist of 760 * the data source. 761 */ 762 public static final int METADATA_KEY_ARTIST = 2; 763 /** 764 * The metadata key to retrieve the information about the author of 765 * the data source. 766 */ 767 public static final int METADATA_KEY_AUTHOR = 3; 768 /** 769 * The metadata key to retrieve the information about the composer of 770 * the data source. 771 */ 772 public static final int METADATA_KEY_COMPOSER = 4; 773 /** 774 * The metadata key to retrieve the date when the data source was created 775 * or modified. 776 */ 777 public static final int METADATA_KEY_DATE = 5; 778 /** 779 * The metadata key to retrieve the content type or genre of the data 780 * source. 781 */ 782 public static final int METADATA_KEY_GENRE = 6; 783 /** 784 * The metadata key to retrieve the data source title. 785 */ 786 public static final int METADATA_KEY_TITLE = 7; 787 /** 788 * The metadata key to retrieve the year when the data source was created 789 * or modified. 790 */ 791 public static final int METADATA_KEY_YEAR = 8; 792 /** 793 * The metadata key to retrieve the playback duration of the data source. 794 */ 795 public static final int METADATA_KEY_DURATION = 9; 796 /** 797 * The metadata key to retrieve the number of tracks, such as audio, video, 798 * text, in the data source, such as a mp4 or 3gpp file. 799 */ 800 public static final int METADATA_KEY_NUM_TRACKS = 10; 801 /** 802 * The metadata key to retrieve the information of the writer (such as 803 * lyricist) of the data source. 804 */ 805 public static final int METADATA_KEY_WRITER = 11; 806 /** 807 * The metadata key to retrieve the mime type of the data source. Some 808 * example mime types include: "video/mp4", "audio/mp4", "audio/amr-wb", 809 * etc. 810 */ 811 public static final int METADATA_KEY_MIMETYPE = 12; 812 /** 813 * The metadata key to retrieve the information about the performers or 814 * artist associated with the data source. 815 */ 816 public static final int METADATA_KEY_ALBUMARTIST = 13; 817 /** 818 * The metadata key to retrieve the numberic string that describes which 819 * part of a set the audio data source comes from. 820 */ 821 public static final int METADATA_KEY_DISC_NUMBER = 14; 822 /** 823 * The metadata key to retrieve the music album compilation status. 824 */ 825 public static final int METADATA_KEY_COMPILATION = 15; 826 /** 827 * If this key exists the media contains audio content. 828 */ 829 public static final int METADATA_KEY_HAS_AUDIO = 16; 830 /** 831 * If this key exists the media contains video content. 832 */ 833 public static final int METADATA_KEY_HAS_VIDEO = 17; 834 /** 835 * If the media contains video, this key retrieves its width. 836 */ 837 public static final int METADATA_KEY_VIDEO_WIDTH = 18; 838 /** 839 * If the media contains video, this key retrieves its height. 840 */ 841 public static final int METADATA_KEY_VIDEO_HEIGHT = 19; 842 /** 843 * This key retrieves the average bitrate (in bits/sec), if available. 844 */ 845 public static final int METADATA_KEY_BITRATE = 20; 846 /** 847 * This key retrieves the language code of text tracks, if available. 848 * If multiple text tracks present, the return value will look like: 849 * "eng:chi" 850 * @hide 851 */ 852 public static final int METADATA_KEY_TIMED_TEXT_LANGUAGES = 21; 853 /** 854 * If this key exists the media is drm-protected. 855 * @hide 856 */ 857 public static final int METADATA_KEY_IS_DRM = 22; 858 /** 859 * This key retrieves the location information, if available. 860 * The location should be specified according to ISO-6709 standard, under 861 * a mp4/3gp box "@xyz". Location with longitude of -90 degrees and latitude 862 * of 180 degrees will be retrieved as "-90.0000+180.0000", for instance. 863 */ 864 public static final int METADATA_KEY_LOCATION = 23; 865 /** 866 * This key retrieves the video rotation angle in degrees, if available. 867 * The video rotation angle may be 0, 90, 180, or 270 degrees. 868 */ 869 public static final int METADATA_KEY_VIDEO_ROTATION = 24; 870 /** 871 * This key retrieves the original capture framerate, if it's 872 * available. The capture framerate will be a floating point 873 * number. 874 */ 875 public static final int METADATA_KEY_CAPTURE_FRAMERATE = 25; 876 /** 877 * If this key exists the media contains still image content. 878 */ 879 public static final int METADATA_KEY_HAS_IMAGE = 26; 880 /** 881 * If the media contains still images, this key retrieves the number 882 * of still images. 883 */ 884 public static final int METADATA_KEY_IMAGE_COUNT = 27; 885 /** 886 * If the media contains still images, this key retrieves the image 887 * index of the primary image. 888 */ 889 public static final int METADATA_KEY_IMAGE_PRIMARY = 28; 890 /** 891 * If the media contains still images, this key retrieves the width 892 * of the primary image. 893 */ 894 public static final int METADATA_KEY_IMAGE_WIDTH = 29; 895 /** 896 * If the media contains still images, this key retrieves the height 897 * of the primary image. 898 */ 899 public static final int METADATA_KEY_IMAGE_HEIGHT = 30; 900 /** 901 * If the media contains still images, this key retrieves the rotation 902 * angle (in degrees clockwise) of the primary image. The image rotation 903 * angle must be one of 0, 90, 180, or 270 degrees. 904 */ 905 public static final int METADATA_KEY_IMAGE_ROTATION = 31; 906 /** 907 * If the media contains video and this key exists, it retrieves the 908 * total number of frames in the video sequence. 909 */ 910 public static final int METADATA_KEY_VIDEO_FRAME_COUNT = 32; 911 912 /** 913 * @hide 914 */ 915 public static final int METADATA_KEY_EXIF_OFFSET = 33; 916 917 /** 918 * @hide 919 */ 920 public static final int METADATA_KEY_EXIF_LENGTH = 34; 921 // Add more here... 922 } 923