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