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 static android.annotation.SystemApi.Client.MODULE_LIBRARIES; 20 21 import android.annotation.IntDef; 22 import android.annotation.IntRange; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.SystemApi; 26 import android.compat.annotation.UnsupportedAppUsage; 27 import android.content.ContentResolver; 28 import android.content.Context; 29 import android.content.res.AssetFileDescriptor; 30 import android.graphics.Bitmap; 31 import android.net.Uri; 32 import android.os.Build; 33 import android.os.Bundle; 34 import android.os.FileUtils; 35 import android.os.IBinder; 36 import android.os.ParcelFileDescriptor; 37 import android.os.SystemProperties; 38 import android.text.TextUtils; 39 import android.util.Log; 40 41 import java.io.FileDescriptor; 42 import java.io.FileInputStream; 43 import java.io.FileNotFoundException; 44 import java.io.IOException; 45 import java.lang.annotation.Retention; 46 import java.lang.annotation.RetentionPolicy; 47 import java.util.HashMap; 48 import java.util.List; 49 import java.util.Map; 50 51 /** 52 * MediaMetadataRetriever class provides a unified interface for retrieving 53 * frame and meta data from an input media file. 54 */ 55 public class MediaMetadataRetriever implements AutoCloseable { 56 private static final String TAG = "MediaMetadataRetriever"; 57 58 // borrowed from ExoPlayer 59 private static final String[] STANDARD_GENRES = new String[] { 60 // These are the official ID3v1 genres. 61 "Blues", 62 "Classic Rock", 63 "Country", 64 "Dance", 65 "Disco", 66 "Funk", 67 "Grunge", 68 "Hip-Hop", 69 "Jazz", 70 "Metal", 71 "New Age", 72 "Oldies", 73 "Other", 74 "Pop", 75 "R&B", 76 "Rap", 77 "Reggae", 78 "Rock", 79 "Techno", 80 "Industrial", 81 "Alternative", 82 "Ska", 83 "Death Metal", 84 "Pranks", 85 "Soundtrack", 86 "Euro-Techno", 87 "Ambient", 88 "Trip-Hop", 89 "Vocal", 90 "Jazz+Funk", 91 "Fusion", 92 "Trance", 93 "Classical", 94 "Instrumental", 95 "Acid", 96 "House", 97 "Game", 98 "Sound Clip", 99 "Gospel", 100 "Noise", 101 "AlternRock", 102 "Bass", 103 "Soul", 104 "Punk", 105 "Space", 106 "Meditative", 107 "Instrumental Pop", 108 "Instrumental Rock", 109 "Ethnic", 110 "Gothic", 111 "Darkwave", 112 "Techno-Industrial", 113 "Electronic", 114 "Pop-Folk", 115 "Eurodance", 116 "Dream", 117 "Southern Rock", 118 "Comedy", 119 "Cult", 120 "Gangsta", 121 "Top 40", 122 "Christian Rap", 123 "Pop/Funk", 124 "Jungle", 125 "Native American", 126 "Cabaret", 127 "New Wave", 128 "Psychadelic", 129 "Rave", 130 "Showtunes", 131 "Trailer", 132 "Lo-Fi", 133 "Tribal", 134 "Acid Punk", 135 "Acid Jazz", 136 "Polka", 137 "Retro", 138 "Musical", 139 "Rock & Roll", 140 "Hard Rock", 141 // These were made up by the authors of Winamp and later added to the ID3 spec. 142 "Folk", 143 "Folk-Rock", 144 "National Folk", 145 "Swing", 146 "Fast Fusion", 147 "Bebob", 148 "Latin", 149 "Revival", 150 "Celtic", 151 "Bluegrass", 152 "Avantgarde", 153 "Gothic Rock", 154 "Progressive Rock", 155 "Psychedelic Rock", 156 "Symphonic Rock", 157 "Slow Rock", 158 "Big Band", 159 "Chorus", 160 "Easy Listening", 161 "Acoustic", 162 "Humour", 163 "Speech", 164 "Chanson", 165 "Opera", 166 "Chamber Music", 167 "Sonata", 168 "Symphony", 169 "Booty Bass", 170 "Primus", 171 "Porn Groove", 172 "Satire", 173 "Slow Jam", 174 "Club", 175 "Tango", 176 "Samba", 177 "Folklore", 178 "Ballad", 179 "Power Ballad", 180 "Rhythmic Soul", 181 "Freestyle", 182 "Duet", 183 "Punk Rock", 184 "Drum Solo", 185 "A capella", 186 "Euro-House", 187 "Dance Hall", 188 // These were made up by the authors of Winamp but have not been added to the ID3 spec. 189 "Goa", 190 "Drum & Bass", 191 "Club-House", 192 "Hardcore", 193 "Terror", 194 "Indie", 195 "BritPop", 196 "Afro-Punk", 197 "Polsk Punk", 198 "Beat", 199 "Christian Gangsta Rap", 200 "Heavy Metal", 201 "Black Metal", 202 "Crossover", 203 "Contemporary Christian", 204 "Christian Rock", 205 "Merengue", 206 "Salsa", 207 "Thrash Metal", 208 "Anime", 209 "Jpop", 210 "Synthpop" 211 }; 212 213 static { 214 System.loadLibrary("media_jni"); native_init()215 native_init(); 216 } 217 218 // The field below is accessed by native methods 219 @SuppressWarnings("unused") 220 private long mNativeContext; 221 222 private static final int EMBEDDED_PICTURE_TYPE_ANY = 0xFFFF; 223 MediaMetadataRetriever()224 public MediaMetadataRetriever() { 225 native_setup(); 226 } 227 228 /** 229 * Sets the data source (file pathname) to use. Call this 230 * method before the rest of the methods in this class. This method may be 231 * time-consuming. 232 * 233 * @param path The path, or the URI (doesn't support streaming source currently) 234 * of the input media file. 235 * @throws IllegalArgumentException If the path is invalid. 236 */ setDataSource(String path)237 public void setDataSource(String path) throws IllegalArgumentException { 238 if (path == null) { 239 throw new IllegalArgumentException("null path"); 240 } 241 242 final Uri uri = Uri.parse(path); 243 final String scheme = uri.getScheme(); 244 if ("file".equals(scheme)) { 245 path = uri.getPath(); 246 } else if (scheme != null) { 247 setDataSource(path, new HashMap<String, String>()); 248 return; 249 } 250 251 try (FileInputStream is = new FileInputStream(path)) { 252 FileDescriptor fd = is.getFD(); 253 setDataSource(fd, 0, 0x7ffffffffffffffL); 254 } catch (FileNotFoundException fileEx) { 255 throw new IllegalArgumentException(path + " does not exist"); 256 } catch (IOException ioEx) { 257 throw new IllegalArgumentException("couldn't open " + path); 258 } 259 } 260 261 /** 262 * Sets the data source (URI) to use. Call this 263 * method before the rest of the methods in this class. This method may be 264 * time-consuming. 265 * 266 * @param uri The URI of the input media. 267 * @param headers the headers to be sent together with the request for the data 268 * @throws IllegalArgumentException If the URI is invalid. 269 */ setDataSource(String uri, Map<String, String> headers)270 public void setDataSource(String uri, Map<String, String> headers) 271 throws IllegalArgumentException { 272 int i = 0; 273 String[] keys = new String[headers.size()]; 274 String[] values = new String[headers.size()]; 275 for (Map.Entry<String, String> entry: headers.entrySet()) { 276 keys[i] = entry.getKey(); 277 values[i] = entry.getValue(); 278 ++i; 279 } 280 281 _setDataSource( 282 MediaHTTPService.createHttpServiceBinderIfNecessary(uri), 283 uri, 284 keys, 285 values); 286 } 287 _setDataSource( IBinder httpServiceBinder, String uri, String[] keys, String[] values)288 private native void _setDataSource( 289 IBinder httpServiceBinder, String uri, String[] keys, String[] values) 290 throws IllegalArgumentException; 291 292 /** 293 * Sets the data source (FileDescriptor) to use. It is the caller's 294 * responsibility to close the file descriptor. It is safe to do so as soon 295 * as this call returns. Call this method before the rest of the methods in 296 * this class. This method may be time-consuming. 297 * 298 * @param fd the FileDescriptor for the file you want to play 299 * @param offset the offset into the file where the data to be played starts, 300 * in bytes. It must be non-negative 301 * @param length the length in bytes of the data to be played. It must be 302 * non-negative. 303 * @throws IllegalArgumentException if the arguments are invalid 304 */ setDataSource(FileDescriptor fd, long offset, long length)305 public void setDataSource(FileDescriptor fd, long offset, long length) 306 throws IllegalArgumentException { 307 308 try (ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd)) { 309 if (modernFd == null) { 310 _setDataSource(fd, offset, length); 311 } else { 312 _setDataSource(modernFd.getFileDescriptor(), offset, length); 313 } 314 } catch (IOException e) { 315 Log.w(TAG, "Ignoring IO error while setting data source", e); 316 } 317 } 318 _setDataSource(FileDescriptor fd, long offset, long length)319 private native void _setDataSource(FileDescriptor fd, long offset, long length) 320 throws IllegalArgumentException; 321 322 /** 323 * Sets the data source (FileDescriptor) to use. It is the caller's 324 * responsibility to close the file descriptor. It is safe to do so as soon 325 * as this call returns. Call this method before the rest of the methods in 326 * this class. This method may be time-consuming. 327 * 328 * @param fd the FileDescriptor for the file you want to play 329 * @throws IllegalArgumentException if the FileDescriptor is invalid 330 */ setDataSource(FileDescriptor fd)331 public void setDataSource(FileDescriptor fd) 332 throws IllegalArgumentException { 333 // intentionally less than LONG_MAX 334 setDataSource(fd, 0, 0x7ffffffffffffffL); 335 } 336 337 /** 338 * Sets the data source as a content Uri. Call this method before 339 * the rest of the methods in this class. This method may be time-consuming. 340 * 341 * @param context the Context to use when resolving the Uri 342 * @param uri the Content URI of the data you want to play 343 * @throws IllegalArgumentException if the Uri is invalid 344 * @throws SecurityException if the Uri cannot be used due to lack of 345 * permission. 346 */ setDataSource(Context context, Uri uri)347 public void setDataSource(Context context, Uri uri) 348 throws IllegalArgumentException, SecurityException { 349 if (uri == null) { 350 throw new IllegalArgumentException("null uri"); 351 } 352 353 String scheme = uri.getScheme(); 354 if(scheme == null || scheme.equals("file")) { 355 setDataSource(uri.getPath()); 356 return; 357 } 358 359 AssetFileDescriptor fd = null; 360 try { 361 ContentResolver resolver = context.getContentResolver(); 362 try { 363 boolean optimize = 364 SystemProperties.getBoolean("fuse.sys.transcode_retriever_optimize", false); 365 Bundle opts = new Bundle(); 366 opts.putBoolean("android.provider.extra.ACCEPT_ORIGINAL_MEDIA_FORMAT", true); 367 fd = optimize ? resolver.openTypedAssetFileDescriptor(uri, "*/*", opts) 368 : resolver.openAssetFileDescriptor(uri, "r"); 369 } catch(FileNotFoundException e) { 370 throw new IllegalArgumentException("could not access " + uri); 371 } 372 if (fd == null) { 373 throw new IllegalArgumentException("got null FileDescriptor for " + uri); 374 } 375 FileDescriptor descriptor = fd.getFileDescriptor(); 376 if (!descriptor.valid()) { 377 throw new IllegalArgumentException("got invalid FileDescriptor for " + uri); 378 } 379 // Note: using getDeclaredLength so that our behavior is the same 380 // as previous versions when the content provider is returning 381 // a full file. 382 if (fd.getDeclaredLength() < 0) { 383 setDataSource(descriptor); 384 } else { 385 setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength()); 386 } 387 return; 388 } catch (SecurityException ex) { 389 } finally { 390 try { 391 if (fd != null) { 392 fd.close(); 393 } 394 } catch(IOException ioEx) { 395 } 396 } 397 setDataSource(uri.toString()); 398 } 399 400 /** 401 * Sets the data source (MediaDataSource) to use. 402 * 403 * @param dataSource the MediaDataSource for the media you want to play 404 */ setDataSource(MediaDataSource dataSource)405 public void setDataSource(MediaDataSource dataSource) 406 throws IllegalArgumentException { 407 _setDataSource(dataSource); 408 } 409 _setDataSource(MediaDataSource dataSource)410 private native void _setDataSource(MediaDataSource dataSource) 411 throws IllegalArgumentException; 412 nativeExtractMetadata(int keyCode)413 private native @Nullable String nativeExtractMetadata(int keyCode); 414 415 /** 416 * Call this method after setDataSource(). This method retrieves the 417 * meta data value associated with the keyCode. 418 * 419 * The keyCode currently supported is listed below as METADATA_XXX 420 * constants. With any other value, it returns a null pointer. 421 * 422 * @param keyCode One of the constants listed below at the end of the class. 423 * @return The meta data value associate with the given keyCode on success; 424 * null on failure. 425 */ extractMetadata(int keyCode)426 public @Nullable String extractMetadata(int keyCode) { 427 String meta = nativeExtractMetadata(keyCode); 428 if (keyCode == METADATA_KEY_GENRE) { 429 // translate numeric genre code(s) to human readable 430 meta = convertGenreTag(meta); 431 } 432 return meta; 433 } 434 435 /* 436 * The id3v2 spec doesn't specify the syntax of the genre tag very precisely, so 437 * some assumptions are made. Using one possible interpretation of the id3v2 438 * spec, this method converts an id3 genre tag string to a human readable string, 439 * as follows: 440 * - if the first character of the tag is a digit, the entire tag is assumed to 441 * be an id3v1 numeric genre code. If the tag does not parse to a number, or 442 * the number is outside the range of defined standard genres, it is ignored. 443 * - if the tag does not start with a digit, it is assumed to be an id3v2 style 444 * tag consisting of one or more genres, with each genre being either a parenthesized 445 * integer referring to an id3v1 numeric genre code, the special indicators "(CR)" or 446 * "(RX)" (for "Cover" or "Remix", respectively), or a custom genre string. When 447 * a custom genre string is encountered, it is assumed to continue until the end 448 * of the tag, unless it starts with "((" in which case it is assumed to continue 449 * until the next close-parenthesis or the end of the tag. Any parse error in the tag 450 * causes it to be ignored. 451 * The human-readable genre string is not localized, and uses the English genre names 452 * from the spec. 453 */ convertGenreTag(String meta)454 private String convertGenreTag(String meta) { 455 if (TextUtils.isEmpty(meta)) { 456 return null; 457 } 458 459 if (Character.isDigit(meta.charAt(0))) { 460 // assume a single id3v1-style bare number without any extra characters 461 try { 462 int genreIndex = Integer.parseInt(meta); 463 if (genreIndex >= 0 && genreIndex < STANDARD_GENRES.length) { 464 return STANDARD_GENRES[genreIndex]; 465 } 466 } catch (NumberFormatException e) { 467 // ignore and fall through 468 } 469 return null; 470 } else { 471 // assume id3v2-style genre tag, with parenthesized numeric genres 472 // and/or literal genre strings, possibly more than one per tag. 473 StringBuilder genres = null; 474 String nextGenre = null; 475 while (true) { 476 if (!TextUtils.isEmpty(nextGenre)) { 477 if (genres == null) { 478 genres = new StringBuilder(); 479 } 480 if (genres.length() != 0) { 481 genres.append(", "); 482 } 483 genres.append(nextGenre); 484 nextGenre = null; 485 } 486 if (TextUtils.isEmpty(meta)) { 487 // entire tag has been processed. 488 break; 489 } 490 if (meta.startsWith("(RX)")) { 491 nextGenre = "Remix"; 492 meta = meta.substring(4); 493 } else if (meta.startsWith("(CR)")) { 494 nextGenre = "Cover"; 495 meta = meta.substring(4); 496 } else if (meta.startsWith("((")) { 497 // the id3v2 spec says that custom genres that start with a parenthesis 498 // should be "escaped" with another parenthesis, however the spec doesn't 499 // specify escaping parentheses inside the custom string. We'll parse any 500 // such strings until a closing parenthesis is found, or the end of 501 // the tag is reached. 502 int closeParenOffset = meta.indexOf(')'); 503 if (closeParenOffset == -1) { 504 // string continues to end of tag 505 nextGenre = meta.substring(1); 506 meta = ""; 507 } else { 508 nextGenre = meta.substring(1, closeParenOffset + 1); 509 meta = meta.substring(closeParenOffset + 1); 510 } 511 } else if (meta.startsWith("(")) { 512 // should be a parenthesized numeric genre 513 int closeParenOffset = meta.indexOf(')'); 514 if (closeParenOffset == -1) { 515 return null; 516 } 517 String genreNumString = meta.substring(1, closeParenOffset); 518 try { 519 int genreIndex = Integer.parseInt(genreNumString.toString()); 520 if (genreIndex >= 0 && genreIndex < STANDARD_GENRES.length) { 521 nextGenre = STANDARD_GENRES[genreIndex]; 522 } else { 523 return null; 524 } 525 } catch (NumberFormatException e) { 526 return null; 527 } 528 meta = meta.substring(closeParenOffset + 1); 529 } else { 530 // custom genre 531 nextGenre = meta; 532 meta = ""; 533 } 534 } 535 return genres == null || genres.length() == 0 ? null : genres.toString(); 536 } 537 } 538 539 /** 540 * This method is similar to {@link #getFrameAtTime(long, int, BitmapParams)} 541 * except that the device will choose the actual {@link Bitmap.Config} to use. 542 * 543 * @param timeUs The time position where the frame will be retrieved. 544 * When retrieving the frame at the given time position, there is no 545 * guarantee that the data source has a frame located at the position. 546 * When this happens, a frame nearby will be returned. If timeUs is 547 * negative, time position and option will ignored, and any frame 548 * that the implementation considers as representative may be returned. 549 * 550 * @param option a hint on how the frame is found. Use 551 * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame 552 * that has a timestamp earlier than or the same as timeUs. Use 553 * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame 554 * that has a timestamp later than or the same as timeUs. Use 555 * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame 556 * that has a timestamp closest to or the same as timeUs. Use 557 * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may 558 * or may not be a sync frame but is closest to or the same as timeUs. 559 * {@link #OPTION_CLOSEST} often has larger performance overhead compared 560 * to the other options if there is no sync frame located at timeUs. 561 * 562 * @return A Bitmap containing a representative video frame, which can be null, 563 * if such a frame cannot be retrieved. {@link Bitmap#getConfig()} can 564 * be used to query the actual {@link Bitmap.Config}. 565 * 566 * @see #getFrameAtTime(long, int, BitmapParams) 567 */ getFrameAtTime(long timeUs, @Option int option)568 public @Nullable Bitmap getFrameAtTime(long timeUs, @Option int option) { 569 if (option < OPTION_PREVIOUS_SYNC || 570 option > OPTION_CLOSEST) { 571 throw new IllegalArgumentException("Unsupported option: " + option); 572 } 573 574 return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/, null); 575 } 576 577 /** 578 * Call this method after setDataSource(). This method finds a 579 * representative frame close to the given time position by considering 580 * the given option if possible, and returns it as a bitmap. 581 * 582 * <p>If you don't need a full-resolution 583 * frame (for example, because you need a thumbnail image), use 584 * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this 585 * method.</p> 586 * 587 * @param timeUs The time position where the frame will be retrieved. 588 * When retrieving the frame at the given time position, there is no 589 * guarantee that the data source has a frame located at the position. 590 * When this happens, a frame nearby will be returned. If timeUs is 591 * negative, time position and option will ignored, and any frame 592 * that the implementation considers as representative may be returned. 593 * 594 * @param option a hint on how the frame is found. Use 595 * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame 596 * that has a timestamp earlier than or the same as timeUs. Use 597 * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame 598 * that has a timestamp later than or the same as timeUs. Use 599 * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame 600 * that has a timestamp closest to or the same as timeUs. Use 601 * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may 602 * or may not be a sync frame but is closest to or the same as timeUs. 603 * {@link #OPTION_CLOSEST} often has larger performance overhead compared 604 * to the other options if there is no sync frame located at timeUs. 605 * 606 * @param params BitmapParams that controls the returned bitmap config 607 * (such as pixel formats). 608 * 609 * @return A Bitmap containing a representative video frame, which 610 * can be null, if such a frame cannot be retrieved. 611 * 612 * @see #getFrameAtTime(long, int) 613 */ getFrameAtTime( long timeUs, @Option int option, @NonNull BitmapParams params)614 public @Nullable Bitmap getFrameAtTime( 615 long timeUs, @Option int option, @NonNull BitmapParams params) { 616 if (option < OPTION_PREVIOUS_SYNC || 617 option > OPTION_CLOSEST) { 618 throw new IllegalArgumentException("Unsupported option: " + option); 619 } 620 621 return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/, params); 622 } 623 624 /** 625 * This method is similar to {@link #getScaledFrameAtTime(long, int, int, int, BitmapParams)} 626 * except that the device will choose the actual {@link Bitmap.Config} to use. 627 * 628 * @param timeUs The time position in microseconds where the frame will be retrieved. 629 * When retrieving the frame at the given time position, there is no 630 * guarantee that the data source has a frame located at the position. 631 * When this happens, a frame nearby will be returned. If timeUs is 632 * negative, time position and option will ignored, and any frame 633 * that the implementation considers as representative may be returned. 634 * 635 * @param option a hint on how the frame is found. Use 636 * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame 637 * that has a timestamp earlier than or the same as timeUs. Use 638 * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame 639 * that has a timestamp later than or the same as timeUs. Use 640 * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame 641 * that has a timestamp closest to or the same as timeUs. Use 642 * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may 643 * or may not be a sync frame but is closest to or the same as timeUs. 644 * {@link #OPTION_CLOSEST} often has larger performance overhead compared 645 * to the other options if there is no sync frame located at timeUs. 646 * 647 * @param dstWidth expected output bitmap width 648 * @param dstHeight expected output bitmap height 649 * @return A Bitmap containing a representative video frame, which can be null, 650 * if such a frame cannot be retrieved. {@link Bitmap#getConfig()} can 651 * be used to query the actual {@link Bitmap.Config}. 652 * @throws IllegalArgumentException if passed in invalid option or width by height 653 * is less than or equal to 0. 654 * @see #getScaledFrameAtTime(long, int, int, int, BitmapParams) 655 */ getScaledFrameAtTime(long timeUs, @Option int option, @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight)656 public @Nullable Bitmap getScaledFrameAtTime(long timeUs, @Option int option, 657 @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight) { 658 validate(option, dstWidth, dstHeight); 659 return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, null); 660 } 661 662 /** 663 * Retrieve a video frame near a given timestamp scaled to a desired size. 664 * Call this method after setDataSource(). This method finds a representative 665 * frame close to the given time position by considering the given option 666 * if possible, and returns it as a bitmap with same aspect ratio as the source 667 * while scaling it so that it fits into the desired size of dst_width by dst_height. 668 * This is useful for generating a thumbnail for an input data source or just to 669 * obtain a scaled frame at the given time position. 670 * 671 * @param timeUs The time position in microseconds where the frame will be retrieved. 672 * When retrieving the frame at the given time position, there is no 673 * guarantee that the data source has a frame located at the position. 674 * When this happens, a frame nearby will be returned. If timeUs is 675 * negative, time position and option will ignored, and any frame 676 * that the implementation considers as representative may be returned. 677 * 678 * @param option a hint on how the frame is found. Use 679 * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame 680 * that has a timestamp earlier than or the same as timeUs. Use 681 * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame 682 * that has a timestamp later than or the same as timeUs. Use 683 * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame 684 * that has a timestamp closest to or the same as timeUs. Use 685 * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may 686 * or may not be a sync frame but is closest to or the same as timeUs. 687 * {@link #OPTION_CLOSEST} often has larger performance overhead compared 688 * to the other options if there is no sync frame located at timeUs. 689 * 690 * @param dstWidth expected output bitmap width 691 * @param dstHeight expected output bitmap height 692 * @param params BitmapParams that controls the returned bitmap config 693 * (such as pixel formats). 694 * 695 * @return A Bitmap of size not larger than dstWidth by dstHeight containing a 696 * scaled video frame, which can be null, if such a frame cannot be retrieved. 697 * @throws IllegalArgumentException if passed in invalid option or width by height 698 * is less than or equal to 0. 699 * @see #getScaledFrameAtTime(long, int, int, int) 700 */ getScaledFrameAtTime(long timeUs, @Option int option, @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight, @NonNull BitmapParams params)701 public @Nullable Bitmap getScaledFrameAtTime(long timeUs, @Option int option, 702 @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight, 703 @NonNull BitmapParams params) { 704 validate(option, dstWidth, dstHeight); 705 return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, params); 706 } 707 validate(@ption int option, int dstWidth, int dstHeight)708 private void validate(@Option int option, int dstWidth, int dstHeight) { 709 if (option < OPTION_PREVIOUS_SYNC || option > OPTION_CLOSEST) { 710 throw new IllegalArgumentException("Unsupported option: " + option); 711 } 712 if (dstWidth <= 0) { 713 throw new IllegalArgumentException("Invalid width: " + dstWidth); 714 } 715 if (dstHeight <= 0) { 716 throw new IllegalArgumentException("Invalid height: " + dstHeight); 717 } 718 } 719 720 /** 721 * Call this method after setDataSource(). This method finds a 722 * representative frame close to the given time position if possible, 723 * and returns it as a bitmap. Call this method if one does not care 724 * how the frame is found as long as it is close to the given time; 725 * otherwise, please call {@link #getFrameAtTime(long, int)}. 726 * 727 * <p>If you don't need a full-resolution 728 * frame (for example, because you need a thumbnail image), use 729 * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this 730 * method.</p> 731 * 732 * @param timeUs The time position where the frame will be retrieved. 733 * When retrieving the frame at the given time position, there is no 734 * guarentee that the data source has a frame located at the position. 735 * When this happens, a frame nearby will be returned. If timeUs is 736 * negative, time position and option will ignored, and any frame 737 * that the implementation considers as representative may be returned. 738 * 739 * @return A Bitmap of size dst_widthxdst_height containing a representative 740 * video frame, which can be null, if such a frame cannot be retrieved. 741 * 742 * @see #getFrameAtTime(long, int) 743 */ getFrameAtTime(long timeUs)744 public @Nullable Bitmap getFrameAtTime(long timeUs) { 745 return getFrameAtTime(timeUs, OPTION_CLOSEST_SYNC); 746 } 747 748 /** 749 * Call this method after setDataSource(). This method finds a 750 * representative frame at any time position if possible, 751 * and returns it as a bitmap. Call this method if one does not 752 * care about where the frame is located; otherwise, please call 753 * {@link #getFrameAtTime(long)} or {@link #getFrameAtTime(long, int)} 754 * 755 * <p>If you don't need a full-resolution 756 * frame (for example, because you need a thumbnail image), use 757 * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this 758 * method.</p> 759 * 760 * @return A Bitmap containing a representative video frame, which 761 * can be null, if such a frame cannot be retrieved. 762 * 763 * @see #getFrameAtTime(long) 764 * @see #getFrameAtTime(long, int) 765 */ getFrameAtTime()766 public @Nullable Bitmap getFrameAtTime() { 767 return _getFrameAtTime( 768 -1, OPTION_CLOSEST_SYNC, -1 /*dst_width*/, -1 /*dst_height*/, null); 769 } 770 _getFrameAtTime( long timeUs, int option, int width, int height, @Nullable BitmapParams params)771 private native Bitmap _getFrameAtTime( 772 long timeUs, int option, int width, int height, @Nullable BitmapParams params); 773 774 public static final class BitmapParams { 775 private Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888; 776 private Bitmap.Config outActualConfig = Bitmap.Config.ARGB_8888; 777 778 /** 779 * Create a default BitmapParams object. By default, it uses {@link Bitmap.Config#ARGB_8888} 780 * as the preferred bitmap config. 781 */ BitmapParams()782 public BitmapParams() {} 783 784 /** 785 * Set the preferred bitmap config for the decoder to decode into. 786 * 787 * If not set, or the request cannot be met, the decoder will output 788 * in {@link Bitmap.Config#ARGB_8888} config by default. 789 * 790 * After decode, the actual config used can be retrieved by {@link #getActualConfig()}. 791 * 792 * @param config the preferred bitmap config to use. 793 */ setPreferredConfig(@onNull Bitmap.Config config)794 public void setPreferredConfig(@NonNull Bitmap.Config config) { 795 if (config == null) { 796 throw new IllegalArgumentException("preferred config can't be null"); 797 } 798 inPreferredConfig = config; 799 } 800 801 /** 802 * Retrieve the preferred bitmap config in the params. 803 * 804 * @return the preferred bitmap config. 805 */ getPreferredConfig()806 public @NonNull Bitmap.Config getPreferredConfig() { 807 return inPreferredConfig; 808 } 809 810 /** 811 * Get the actual bitmap config used to decode the bitmap after the decoding. 812 * 813 * @return the actual bitmap config used. 814 */ getActualConfig()815 public @NonNull Bitmap.Config getActualConfig() { 816 return outActualConfig; 817 } 818 } 819 820 /** 821 * This method retrieves a video frame by its index. It should only be called 822 * after {@link #setDataSource}. 823 * 824 * After the bitmap is returned, you can query the actual parameters that were 825 * used to create the bitmap from the {@code BitmapParams} argument, for instance 826 * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}. 827 * 828 * @param frameIndex 0-based index of the video frame. The frame index must be that of 829 * a valid frame. The total number of frames available for retrieval can be queried 830 * via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key. 831 * @param params BitmapParams that controls the returned bitmap config (such as pixel formats). 832 * 833 * @throws IllegalStateException if the container doesn't contain video or image sequences. 834 * @throws IllegalArgumentException if the requested frame index does not exist. 835 * 836 * @return A Bitmap containing the requested video frame, or null if the retrieval fails. 837 * 838 * @see #getFrameAtIndex(int) 839 * @see #getFramesAtIndex(int, int, BitmapParams) 840 * @see #getFramesAtIndex(int, int) 841 */ getFrameAtIndex(int frameIndex, @NonNull BitmapParams params)842 public @Nullable Bitmap getFrameAtIndex(int frameIndex, @NonNull BitmapParams params) { 843 List<Bitmap> bitmaps = getFramesAtIndex(frameIndex, 1, params); 844 return bitmaps.get(0); 845 } 846 847 /** 848 * This method is similar to {@link #getFrameAtIndex(int, BitmapParams)} except that 849 * the default for {@link BitmapParams} will be used. 850 * 851 * @param frameIndex 0-based index of the video frame. The frame index must be that of 852 * a valid frame. The total number of frames available for retrieval can be queried 853 * via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key. 854 * 855 * @throws IllegalStateException if the container doesn't contain video or image sequences. 856 * @throws IllegalArgumentException if the requested frame index does not exist. 857 * 858 * @return A Bitmap containing the requested video frame, or null if the retrieval fails. 859 * 860 * @see #getFrameAtIndex(int, BitmapParams) 861 * @see #getFramesAtIndex(int, int, BitmapParams) 862 * @see #getFramesAtIndex(int, int) 863 */ getFrameAtIndex(int frameIndex)864 public @Nullable Bitmap getFrameAtIndex(int frameIndex) { 865 List<Bitmap> bitmaps = getFramesAtIndex(frameIndex, 1); 866 return bitmaps.get(0); 867 } 868 869 /** 870 * This method retrieves a consecutive set of video frames starting at the 871 * specified index. It should only be called after {@link #setDataSource}. 872 * 873 * If the caller intends to retrieve more than one consecutive video frames, 874 * this method is preferred over {@link #getFrameAtIndex(int, BitmapParams)} for efficiency. 875 * 876 * After the bitmaps are returned, you can query the actual parameters that were 877 * used to create the bitmaps from the {@code BitmapParams} argument, for instance 878 * to query the bitmap config used for the bitmaps with {@link BitmapParams#getActualConfig}. 879 * 880 * @param frameIndex 0-based index of the first video frame to retrieve. The frame index 881 * must be that of a valid frame. The total number of frames available for retrieval 882 * can be queried via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key. 883 * @param numFrames number of consecutive video frames to retrieve. Must be a positive 884 * value. The stream must contain at least numFrames frames starting at frameIndex. 885 * @param params BitmapParams that controls the returned bitmap config (such as pixel formats). 886 * 887 * @throws IllegalStateException if the container doesn't contain video or image sequences. 888 * @throws IllegalArgumentException if the frameIndex or numFrames is invalid, or the 889 * stream doesn't contain at least numFrames starting at frameIndex. 890 891 * @return An list of Bitmaps containing the requested video frames. The returned 892 * array could contain less frames than requested if the retrieval fails. 893 * 894 * @see #getFrameAtIndex(int, BitmapParams) 895 * @see #getFrameAtIndex(int) 896 * @see #getFramesAtIndex(int, int) 897 */ getFramesAtIndex( int frameIndex, int numFrames, @NonNull BitmapParams params)898 public @NonNull List<Bitmap> getFramesAtIndex( 899 int frameIndex, int numFrames, @NonNull BitmapParams params) { 900 return getFramesAtIndexInternal(frameIndex, numFrames, params); 901 } 902 903 /** 904 * This method is similar to {@link #getFramesAtIndex(int, int, BitmapParams)} except that 905 * the default for {@link BitmapParams} will be used. 906 * 907 * @param frameIndex 0-based index of the first video frame to retrieve. The frame index 908 * must be that of a valid frame. The total number of frames available for retrieval 909 * can be queried via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key. 910 * @param numFrames number of consecutive video frames to retrieve. Must be a positive 911 * value. The stream must contain at least numFrames frames starting at frameIndex. 912 * 913 * @throws IllegalStateException if the container doesn't contain video or image sequences. 914 * @throws IllegalArgumentException if the frameIndex or numFrames is invalid, or the 915 * stream doesn't contain at least numFrames starting at frameIndex. 916 917 * @return An list of Bitmaps containing the requested video frames. The returned 918 * array could contain less frames than requested if the retrieval fails. 919 * 920 * @see #getFrameAtIndex(int, BitmapParams) 921 * @see #getFrameAtIndex(int) 922 * @see #getFramesAtIndex(int, int, BitmapParams) 923 */ getFramesAtIndex(int frameIndex, int numFrames)924 public @NonNull List<Bitmap> getFramesAtIndex(int frameIndex, int numFrames) { 925 return getFramesAtIndexInternal(frameIndex, numFrames, null); 926 } 927 getFramesAtIndexInternal( int frameIndex, int numFrames, @Nullable BitmapParams params)928 private @NonNull List<Bitmap> getFramesAtIndexInternal( 929 int frameIndex, int numFrames, @Nullable BitmapParams params) { 930 if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO))) { 931 throw new IllegalStateException("Does not contain video or image sequences"); 932 } 933 int frameCount = Integer.parseInt( 934 extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT)); 935 if (frameIndex < 0 || numFrames < 1 936 || frameIndex >= frameCount 937 || frameIndex > frameCount - numFrames) { 938 throw new IllegalArgumentException("Invalid frameIndex or numFrames: " 939 + frameIndex + ", " + numFrames); 940 } 941 return _getFrameAtIndex(frameIndex, numFrames, params); 942 } 943 _getFrameAtIndex( int frameIndex, int numFrames, @Nullable BitmapParams params)944 private native @NonNull List<Bitmap> _getFrameAtIndex( 945 int frameIndex, int numFrames, @Nullable BitmapParams params); 946 947 /** 948 * This method retrieves a still image by its index. It should only be called 949 * after {@link #setDataSource}. 950 * 951 * After the bitmap is returned, you can query the actual parameters that were 952 * used to create the bitmap from the {@code BitmapParams} argument, for instance 953 * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}. 954 * 955 * @param imageIndex 0-based index of the image. 956 * @param params BitmapParams that controls the returned bitmap config (such as pixel formats). 957 * 958 * @throws IllegalStateException if the container doesn't contain still images. 959 * @throws IllegalArgumentException if the requested image does not exist. 960 * 961 * @return the requested still image, or null if the image cannot be retrieved. 962 * 963 * @see #getImageAtIndex(int) 964 * @see #getPrimaryImage(BitmapParams) 965 * @see #getPrimaryImage() 966 */ getImageAtIndex(int imageIndex, @NonNull BitmapParams params)967 public @Nullable Bitmap getImageAtIndex(int imageIndex, @NonNull BitmapParams params) { 968 return getImageAtIndexInternal(imageIndex, params); 969 } 970 971 /** 972 * @hide 973 * 974 * This method retrieves the thumbnail image for a still image if it's available. 975 * It should only be called after {@link #setDataSource}. 976 * 977 * @param imageIndex 0-based index of the image, negative value indicates primary image. 978 * @param params BitmapParams that controls the returned bitmap config (such as pixel formats). 979 * @param targetSize intended size of one edge (wdith or height) of the thumbnail, 980 * this is a heuristic for the framework to decide whether the embedded 981 * thumbnail should be used. 982 * @param maxPixels maximum pixels of thumbnail, this is a heuristic for the frameowrk to 983 * decide whehther the embedded thumnbail (or a downscaled version of it) 984 * should be used. 985 * @return the retrieved thumbnail, or null if no suitable thumbnail is available. 986 */ getThumbnailImageAtIndex( int imageIndex, @NonNull BitmapParams params, int targetSize, int maxPixels)987 public native @Nullable Bitmap getThumbnailImageAtIndex( 988 int imageIndex, @NonNull BitmapParams params, int targetSize, int maxPixels); 989 990 /** 991 * This method is similar to {@link #getImageAtIndex(int, BitmapParams)} except that 992 * the default for {@link BitmapParams} will be used. 993 * 994 * @param imageIndex 0-based index of the image. 995 * 996 * @throws IllegalStateException if the container doesn't contain still images. 997 * @throws IllegalArgumentException if the requested image does not exist. 998 * 999 * @return the requested still image, or null if the image cannot be retrieved. 1000 * 1001 * @see #getImageAtIndex(int, BitmapParams) 1002 * @see #getPrimaryImage(BitmapParams) 1003 * @see #getPrimaryImage() 1004 */ getImageAtIndex(int imageIndex)1005 public @Nullable Bitmap getImageAtIndex(int imageIndex) { 1006 return getImageAtIndexInternal(imageIndex, null); 1007 } 1008 1009 /** 1010 * This method retrieves the primary image of the media content. It should only 1011 * be called after {@link #setDataSource}. 1012 * 1013 * After the bitmap is returned, you can query the actual parameters that were 1014 * used to create the bitmap from the {@code BitmapParams} argument, for instance 1015 * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}. 1016 * 1017 * @param params BitmapParams that controls the returned bitmap config (such as pixel formats). 1018 * 1019 * @return the primary image, or null if it cannot be retrieved. 1020 * 1021 * @throws IllegalStateException if the container doesn't contain still images. 1022 * 1023 * @see #getImageAtIndex(int, BitmapParams) 1024 * @see #getImageAtIndex(int) 1025 * @see #getPrimaryImage() 1026 */ getPrimaryImage(@onNull BitmapParams params)1027 public @Nullable Bitmap getPrimaryImage(@NonNull BitmapParams params) { 1028 return getImageAtIndexInternal(-1, params); 1029 } 1030 1031 /** 1032 * This method is similar to {@link #getPrimaryImage(BitmapParams)} except that 1033 * the default for {@link BitmapParams} will be used. 1034 * 1035 * @return the primary image, or null if it cannot be retrieved. 1036 * 1037 * @throws IllegalStateException if the container doesn't contain still images. 1038 * 1039 * @see #getImageAtIndex(int, BitmapParams) 1040 * @see #getImageAtIndex(int) 1041 * @see #getPrimaryImage(BitmapParams) 1042 */ getPrimaryImage()1043 public @Nullable Bitmap getPrimaryImage() { 1044 return getImageAtIndexInternal(-1, null); 1045 } 1046 getImageAtIndexInternal(int imageIndex, @Nullable BitmapParams params)1047 private Bitmap getImageAtIndexInternal(int imageIndex, @Nullable BitmapParams params) { 1048 if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE))) { 1049 throw new IllegalStateException("Does not contain still images"); 1050 } 1051 1052 String imageCount = extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT); 1053 if (imageIndex >= Integer.parseInt(imageCount)) { 1054 throw new IllegalArgumentException("Invalid image index: " + imageCount); 1055 } 1056 1057 return _getImageAtIndex(imageIndex, params); 1058 } 1059 _getImageAtIndex(int imageIndex, @Nullable BitmapParams params)1060 private native Bitmap _getImageAtIndex(int imageIndex, @Nullable BitmapParams params); 1061 1062 /** 1063 * Call this method after setDataSource(). This method finds the optional 1064 * graphic or album/cover art associated associated with the data source. If 1065 * there are more than one pictures, (any) one of them is returned. 1066 * 1067 * @return null if no such graphic is found. 1068 */ getEmbeddedPicture()1069 public @Nullable byte[] getEmbeddedPicture() { 1070 return getEmbeddedPicture(EMBEDDED_PICTURE_TYPE_ANY); 1071 } 1072 1073 @UnsupportedAppUsage getEmbeddedPicture(int pictureType)1074 private native byte[] getEmbeddedPicture(int pictureType); 1075 1076 /** 1077 * Releases any acquired resources. Call it when done with the object. 1078 * 1079 * @throws IOException When an {@link IOException} is thrown while closing a {@link 1080 * MediaDataSource} passed to {@link #setDataSource(MediaDataSource)}. This throws clause exists 1081 * since API {@link android.os.Build.VERSION_CODES#TIRAMISU}, but this method can throw in 1082 * earlier API versions where the exception is not declared. 1083 */ 1084 @Override close()1085 public void close() throws IOException { 1086 release(); 1087 } 1088 1089 /** 1090 * Releases any acquired resources. Call it when done with the object. 1091 * 1092 * @throws IOException When an {@link IOException} is thrown while closing a {@link 1093 * MediaDataSource} passed to {@link #setDataSource(MediaDataSource)}. This throws clause exists 1094 * since API {@link android.os.Build.VERSION_CODES#TIRAMISU}, but this method can throw in 1095 * earlier API versions where the exception is not declared. 1096 */ release()1097 public native void release() throws IOException; 1098 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) native_setup()1099 private native void native_setup(); 1100 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) native_init()1101 private static native void native_init(); 1102 1103 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) native_finalize()1104 private native final void native_finalize(); 1105 1106 @Override finalize()1107 protected void finalize() throws Throwable { 1108 try { 1109 native_finalize(); 1110 } finally { 1111 super.finalize(); 1112 } 1113 } 1114 1115 /** 1116 * Option used in method {@link #getFrameAtTime(long, int)} to get a 1117 * frame at a specified location. 1118 * 1119 * @see #getFrameAtTime(long, int) 1120 */ 1121 /* Do not change these option values without updating their counterparts 1122 * in include/media/MediaSource.h! 1123 */ 1124 /** 1125 * This option is used with {@link #getFrameAtTime(long, int)} to retrieve 1126 * a sync (or key) frame associated with a data source that is located 1127 * right before or at the given time. 1128 * 1129 * @see #getFrameAtTime(long, int) 1130 */ 1131 public static final int OPTION_PREVIOUS_SYNC = 0x00; 1132 /** 1133 * This option is used with {@link #getFrameAtTime(long, int)} to retrieve 1134 * a sync (or key) frame associated with a data source that is located 1135 * right after or at the given time. 1136 * 1137 * @see #getFrameAtTime(long, int) 1138 */ 1139 public static final int OPTION_NEXT_SYNC = 0x01; 1140 /** 1141 * This option is used with {@link #getFrameAtTime(long, int)} to retrieve 1142 * a sync (or key) frame associated with a data source that is located 1143 * closest to (in time) or at the given time. 1144 * 1145 * @see #getFrameAtTime(long, int) 1146 */ 1147 public static final int OPTION_CLOSEST_SYNC = 0x02; 1148 /** 1149 * This option is used with {@link #getFrameAtTime(long, int)} to retrieve 1150 * a frame (not necessarily a key frame) associated with a data source that 1151 * is located closest to or at the given time. 1152 * 1153 * @see #getFrameAtTime(long, int) 1154 */ 1155 public static final int OPTION_CLOSEST = 0x03; 1156 1157 /** @hide */ 1158 @IntDef(flag = false, prefix = { "OPTION_" }, value = { 1159 OPTION_PREVIOUS_SYNC, 1160 OPTION_NEXT_SYNC, 1161 OPTION_CLOSEST_SYNC, 1162 OPTION_CLOSEST, 1163 }) 1164 @Retention(RetentionPolicy.SOURCE) 1165 public @interface Option {} 1166 1167 /* 1168 * Do not change these metadata key values without updating their 1169 * counterparts in include/media/mediametadataretriever.h! 1170 */ 1171 /** 1172 * The metadata key to retrieve the numeric string describing the 1173 * order of the audio data source on its original recording. 1174 */ 1175 public static final int METADATA_KEY_CD_TRACK_NUMBER = 0; 1176 /** 1177 * The metadata key to retrieve the information about the album title 1178 * of the data source. 1179 */ 1180 public static final int METADATA_KEY_ALBUM = 1; 1181 /** 1182 * The metadata key to retrieve the information about the artist of 1183 * the data source. 1184 */ 1185 public static final int METADATA_KEY_ARTIST = 2; 1186 /** 1187 * The metadata key to retrieve the information about the author of 1188 * the data source. 1189 */ 1190 public static final int METADATA_KEY_AUTHOR = 3; 1191 /** 1192 * The metadata key to retrieve the information about the composer of 1193 * the data source. 1194 */ 1195 public static final int METADATA_KEY_COMPOSER = 4; 1196 /** 1197 * The metadata key to retrieve the date when the data source was created 1198 * or modified. 1199 */ 1200 public static final int METADATA_KEY_DATE = 5; 1201 /** 1202 * The metadata key to retrieve the content type or genre of the data 1203 * source. 1204 */ 1205 public static final int METADATA_KEY_GENRE = 6; 1206 /** 1207 * The metadata key to retrieve the data source title. 1208 */ 1209 public static final int METADATA_KEY_TITLE = 7; 1210 /** 1211 * The metadata key to retrieve the year when the data source was created 1212 * or modified. 1213 */ 1214 public static final int METADATA_KEY_YEAR = 8; 1215 /** 1216 * The metadata key to retrieve the playback duration (in ms) of the data source. 1217 */ 1218 public static final int METADATA_KEY_DURATION = 9; 1219 /** 1220 * The metadata key to retrieve the number of tracks, such as audio, video, 1221 * text, in the data source, such as a mp4 or 3gpp file. 1222 */ 1223 public static final int METADATA_KEY_NUM_TRACKS = 10; 1224 /** 1225 * The metadata key to retrieve the information of the writer (such as 1226 * lyricist) of the data source. 1227 */ 1228 public static final int METADATA_KEY_WRITER = 11; 1229 /** 1230 * The metadata key to retrieve the mime type of the data source. Some 1231 * example mime types include: "video/mp4", "audio/mp4", "audio/amr-wb", 1232 * etc. 1233 */ 1234 public static final int METADATA_KEY_MIMETYPE = 12; 1235 /** 1236 * The metadata key to retrieve the information about the performers or 1237 * artist associated with the data source. 1238 */ 1239 public static final int METADATA_KEY_ALBUMARTIST = 13; 1240 /** 1241 * The metadata key to retrieve the numberic string that describes which 1242 * part of a set the audio data source comes from. 1243 */ 1244 public static final int METADATA_KEY_DISC_NUMBER = 14; 1245 /** 1246 * The metadata key to retrieve the music album compilation status. 1247 */ 1248 public static final int METADATA_KEY_COMPILATION = 15; 1249 /** 1250 * If this key exists the media contains audio content. 1251 */ 1252 public static final int METADATA_KEY_HAS_AUDIO = 16; 1253 /** 1254 * If this key exists the media contains video content. 1255 */ 1256 public static final int METADATA_KEY_HAS_VIDEO = 17; 1257 /** 1258 * If the media contains video, this key retrieves its width. 1259 */ 1260 public static final int METADATA_KEY_VIDEO_WIDTH = 18; 1261 /** 1262 * If the media contains video, this key retrieves its height. 1263 */ 1264 public static final int METADATA_KEY_VIDEO_HEIGHT = 19; 1265 /** 1266 * This key retrieves the average bitrate (in bits/sec), if available. 1267 */ 1268 public static final int METADATA_KEY_BITRATE = 20; 1269 /** 1270 * This key retrieves the language code of text tracks, if available. 1271 * If multiple text tracks present, the return value will look like: 1272 * "eng:chi" 1273 * @hide 1274 */ 1275 public static final int METADATA_KEY_TIMED_TEXT_LANGUAGES = 21; 1276 /** 1277 * If this key exists the media is drm-protected. 1278 * @hide 1279 */ 1280 public static final int METADATA_KEY_IS_DRM = 22; 1281 /** 1282 * This key retrieves the location information, if available. 1283 * The location should be specified according to ISO-6709 standard, under 1284 * a mp4/3gp box "@xyz". Location with longitude of -90 degrees and latitude 1285 * of 180 degrees will be retrieved as "+180.0000-90.0000/", for instance. 1286 */ 1287 public static final int METADATA_KEY_LOCATION = 23; 1288 /** 1289 * This key retrieves the video rotation angle in degrees, if available. 1290 * The video rotation angle may be 0, 90, 180, or 270 degrees. 1291 */ 1292 public static final int METADATA_KEY_VIDEO_ROTATION = 24; 1293 /** 1294 * This key retrieves the original capture framerate, if it's 1295 * available. The capture framerate will be a floating point 1296 * number. 1297 */ 1298 public static final int METADATA_KEY_CAPTURE_FRAMERATE = 25; 1299 /** 1300 * If this key exists the media contains still image content. 1301 */ 1302 public static final int METADATA_KEY_HAS_IMAGE = 26; 1303 /** 1304 * If the media contains still images, this key retrieves the number 1305 * of still images. 1306 */ 1307 public static final int METADATA_KEY_IMAGE_COUNT = 27; 1308 /** 1309 * If the media contains still images, this key retrieves the image 1310 * index of the primary image. 1311 */ 1312 public static final int METADATA_KEY_IMAGE_PRIMARY = 28; 1313 /** 1314 * If the media contains still images, this key retrieves the width 1315 * of the primary image. 1316 */ 1317 public static final int METADATA_KEY_IMAGE_WIDTH = 29; 1318 /** 1319 * If the media contains still images, this key retrieves the height 1320 * of the primary image. 1321 */ 1322 public static final int METADATA_KEY_IMAGE_HEIGHT = 30; 1323 /** 1324 * If the media contains still images, this key retrieves the rotation 1325 * angle (in degrees clockwise) of the primary image. The image rotation 1326 * angle must be one of 0, 90, 180, or 270 degrees. 1327 */ 1328 public static final int METADATA_KEY_IMAGE_ROTATION = 31; 1329 /** 1330 * If the media contains video and this key exists, it retrieves the 1331 * total number of frames in the video sequence. 1332 */ 1333 public static final int METADATA_KEY_VIDEO_FRAME_COUNT = 32; 1334 1335 /** 1336 * If the media contains EXIF data, this key retrieves the offset (in bytes) 1337 * of the data. 1338 */ 1339 public static final int METADATA_KEY_EXIF_OFFSET = 33; 1340 1341 /** 1342 * If the media contains EXIF data, this key retrieves the length (in bytes) 1343 * of the data. 1344 */ 1345 public static final int METADATA_KEY_EXIF_LENGTH = 34; 1346 1347 /** 1348 * This key retrieves the color standard, if available. 1349 * 1350 * @see MediaFormat#COLOR_STANDARD_BT709 1351 * @see MediaFormat#COLOR_STANDARD_BT601_PAL 1352 * @see MediaFormat#COLOR_STANDARD_BT601_NTSC 1353 * @see MediaFormat#COLOR_STANDARD_BT2020 1354 */ 1355 public static final int METADATA_KEY_COLOR_STANDARD = 35; 1356 1357 /** 1358 * This key retrieves the color transfer, if available. 1359 * 1360 * @see MediaFormat#COLOR_TRANSFER_LINEAR 1361 * @see MediaFormat#COLOR_TRANSFER_SDR_VIDEO 1362 * @see MediaFormat#COLOR_TRANSFER_ST2084 1363 * @see MediaFormat#COLOR_TRANSFER_HLG 1364 */ 1365 public static final int METADATA_KEY_COLOR_TRANSFER = 36; 1366 1367 /** 1368 * This key retrieves the color range, if available. 1369 * 1370 * @see MediaFormat#COLOR_RANGE_LIMITED 1371 * @see MediaFormat#COLOR_RANGE_FULL 1372 */ 1373 public static final int METADATA_KEY_COLOR_RANGE = 37; 1374 1375 /** 1376 * This key retrieves the sample rate in Hz, if available. 1377 * This is a signed 32-bit integer formatted as a string in base 10. 1378 */ 1379 public static final int METADATA_KEY_SAMPLERATE = 38; 1380 1381 /** 1382 * This key retrieves the bits per sample in numbers of bits, if available. 1383 * This is a signed 32-bit integer formatted as a string in base 10. 1384 */ 1385 public static final int METADATA_KEY_BITS_PER_SAMPLE = 39; 1386 1387 /** 1388 * This key retrieves the video codec mimetype if available. 1389 * @hide 1390 */ 1391 @SystemApi(client = MODULE_LIBRARIES) 1392 public static final int METADATA_KEY_VIDEO_CODEC_MIME_TYPE = 40; 1393 1394 /** 1395 * If the media contains XMP data, this key retrieves the offset (in bytes) 1396 * of the data. 1397 */ 1398 public static final int METADATA_KEY_XMP_OFFSET = 41; 1399 1400 /** 1401 * If the media contains XMP data, this key retrieves the length (in bytes) 1402 * of the data. 1403 */ 1404 public static final int METADATA_KEY_XMP_LENGTH = 42; 1405 1406 // Add more here... 1407 } 1408