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