diff options
-rw-r--r-- | api/current.txt | 2 | ||||
-rw-r--r-- | media/java/android/media/MediaMetadataRetriever.java | 110 | ||||
-rw-r--r-- | media/jni/android_media_MediaMetadataRetriever.cpp | 19 |
3 files changed, 115 insertions, 16 deletions
diff --git a/api/current.txt b/api/current.txt index 3a768ea98eb2..dda327f19f41 100644 --- a/api/current.txt +++ b/api/current.txt @@ -25387,6 +25387,7 @@ package android.media { method public android.graphics.Bitmap getFrameAtIndex(int, @NonNull android.media.MediaMetadataRetriever.BitmapParams); method public android.graphics.Bitmap getFrameAtIndex(int); method public android.graphics.Bitmap getFrameAtTime(long, int); + method public android.graphics.Bitmap getFrameAtTime(long, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams); method public android.graphics.Bitmap getFrameAtTime(long); method public android.graphics.Bitmap getFrameAtTime(); method @NonNull public java.util.List<android.graphics.Bitmap> getFramesAtIndex(int, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams); @@ -25396,6 +25397,7 @@ package android.media { method public android.graphics.Bitmap getPrimaryImage(@NonNull android.media.MediaMetadataRetriever.BitmapParams); method public android.graphics.Bitmap getPrimaryImage(); method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int); + method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams); method public void release(); method public void setDataSource(String) throws java.lang.IllegalArgumentException; method public void setDataSource(String, java.util.Map<java.lang.String,java.lang.String>) throws java.lang.IllegalArgumentException; diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java index 0346010f4587..f421029909bd 100644 --- a/media/java/android/media/MediaMetadataRetriever.java +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -227,6 +227,44 @@ public class MediaMetadataRetriever implements AutoCloseable { public native String extractMetadata(int keyCode); /** + * This method is similar to {@link #getFrameAtTime(long, int, BitmapParams)} + * except that the device will choose the actual {@link Bitmap.Config} to use. + * + * @param timeUs The time position where the frame will be retrieved. + * When retrieving the frame at the given time position, there is no + * guarantee that the data source has a frame located at the position. + * When this happens, a frame nearby will be returned. If timeUs is + * negative, time position and option will ignored, and any frame + * that the implementation considers as representative may be returned. + * + * @param option a hint on how the frame is found. Use + * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame + * that has a timestamp earlier than or the same as timeUs. Use + * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame + * that has a timestamp later than or the same as timeUs. Use + * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame + * that has a timestamp closest to or the same as timeUs. Use + * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may + * or may not be a sync frame but is closest to or the same as timeUs. + * {@link #OPTION_CLOSEST} often has larger performance overhead compared + * to the other options if there is no sync frame located at timeUs. + * + * @return A Bitmap containing a representative video frame, which can be null, + * if such a frame cannot be retrieved. {@link Bitmap#getConfig()} can + * be used to query the actual {@link Bitmap.Config}. + * + * @see {@link #getFrameAtTime(long, int, BitmapParams)} + */ + public Bitmap getFrameAtTime(long timeUs, @Option int option) { + if (option < OPTION_PREVIOUS_SYNC || + option > OPTION_CLOSEST) { + throw new IllegalArgumentException("Unsupported option: " + option); + } + + return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/, null); + } + + /** * Call this method after setDataSource(). This method finds a * representative frame close to the given time position by considering * the given option if possible, and returns it as a bitmap. @@ -255,16 +293,60 @@ public class MediaMetadataRetriever implements AutoCloseable { * {@link #OPTION_CLOSEST} often has larger performance overhead compared * to the other options if there is no sync frame located at timeUs. * + * @param params BitmapParams that controls the returned bitmap config + * (such as pixel formats). + * * @return A Bitmap containing a representative video frame, which * can be null, if such a frame cannot be retrieved. + * + * @see {@link #getFrameAtTime(long, int)} */ - public Bitmap getFrameAtTime(long timeUs, @Option int option) { + public Bitmap getFrameAtTime( + long timeUs, @Option int option, @NonNull BitmapParams params) { if (option < OPTION_PREVIOUS_SYNC || option > OPTION_CLOSEST) { throw new IllegalArgumentException("Unsupported option: " + option); } - return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/); + return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/, params); + } + + /** + * This method is similar to {@link #getScaledFrameAtTime(long, int, int, int, BitmapParams)} + * except that the device will choose the actual {@link Bitmap.Config} to use. + * + * @param timeUs The time position in microseconds where the frame will be retrieved. + * When retrieving the frame at the given time position, there is no + * guarantee that the data source has a frame located at the position. + * When this happens, a frame nearby will be returned. If timeUs is + * negative, time position and option will ignored, and any frame + * that the implementation considers as representative may be returned. + * + * @param option a hint on how the frame is found. Use + * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame + * that has a timestamp earlier than or the same as timeUs. Use + * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame + * that has a timestamp later than or the same as timeUs. Use + * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame + * that has a timestamp closest to or the same as timeUs. Use + * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may + * or may not be a sync frame but is closest to or the same as timeUs. + * {@link #OPTION_CLOSEST} often has larger performance overhead compared + * to the other options if there is no sync frame located at timeUs. + * + * @param dstWidth expected output bitmap width + * @param dstHeight expected output bitmap height + * @return A Bitmap containing a representative video frame, which can be null, + * if such a frame cannot be retrieved. {@link Bitmap#getConfig()} can + * be used to query the actual {@link Bitmap.Config}. + * @throws IllegalArgumentException if passed in invalid option or width by height + * is less than or equal to 0. + * @see {@link #getScaledFrameAtTime(long, int, int, int, BitmapParams)} + */ + public Bitmap getScaledFrameAtTime( + long timeUs, @Option int option, int dstWidth, int dstHeight) { + validate(option, dstWidth, dstHeight); + return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, null); } /** @@ -297,15 +379,23 @@ public class MediaMetadataRetriever implements AutoCloseable { * * @param dstWidth expected output bitmap width * @param dstHeight expected output bitmap height + * @param params BitmapParams that controls the returned bitmap config + * (such as pixel formats). + * * @return A Bitmap of size not larger than dstWidth by dstHeight containing a * scaled video frame, which can be null, if such a frame cannot be retrieved. * @throws IllegalArgumentException if passed in invalid option or width by height * is less than or equal to 0. + * @see {@link #getScaledFrameAtTime(long, int, int, int)} */ - public Bitmap getScaledFrameAtTime( - long timeUs, @Option int option, int dstWidth, int dstHeight) { - if (option < OPTION_PREVIOUS_SYNC || - option > OPTION_CLOSEST) { + public Bitmap getScaledFrameAtTime(long timeUs, @Option int option, + int dstWidth, int dstHeight, @NonNull BitmapParams params) { + validate(option, dstWidth, dstHeight); + return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, params); + } + + private void validate(@Option int option, int dstWidth, int dstHeight) { + if (option < OPTION_PREVIOUS_SYNC || option > OPTION_CLOSEST) { throw new IllegalArgumentException("Unsupported option: " + option); } if (dstWidth <= 0) { @@ -314,8 +404,6 @@ public class MediaMetadataRetriever implements AutoCloseable { if (dstHeight <= 0) { throw new IllegalArgumentException("Invalid height: " + dstHeight); } - - return _getFrameAtTime(timeUs, option, dstWidth, dstHeight); } /** @@ -365,10 +453,12 @@ public class MediaMetadataRetriever implements AutoCloseable { * @see #getFrameAtTime(long, int) */ public Bitmap getFrameAtTime() { - return _getFrameAtTime(-1, OPTION_CLOSEST_SYNC, -1 /*dst_width*/, -1 /*dst_height*/); + return _getFrameAtTime( + -1, OPTION_CLOSEST_SYNC, -1 /*dst_width*/, -1 /*dst_height*/, null); } - private native Bitmap _getFrameAtTime(long timeUs, int option, int width, int height); + private native Bitmap _getFrameAtTime( + long timeUs, int option, int width, int height, @Nullable BitmapParams params); public static final class BitmapParams { private Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888; diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 18fd1a01cfd6..bc4bcebaf560 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -350,9 +350,10 @@ static jobject getBitmapFromVideoFrame( return jBitmap; } -static int getColorFormat(JNIEnv *env, jobject options) { +static int getColorFormat(JNIEnv *env, jobject options, + int defaultPreferred = HAL_PIXEL_FORMAT_RGBA_8888) { if (options == NULL) { - return HAL_PIXEL_FORMAT_RGBA_8888; + return defaultPreferred; } ScopedLocalRef<jobject> inConfig(env, env->GetObjectField(options, fields.inPreferredConfig)); @@ -383,7 +384,8 @@ static SkColorType setOutColorType(JNIEnv *env, int colorFormat, jobject options } static jobject android_media_MediaMetadataRetriever_getFrameAtTime( - JNIEnv *env, jobject thiz, jlong timeUs, jint option, jint dst_width, jint dst_height) + JNIEnv *env, jobject thiz, jlong timeUs, jint option, + jint dst_width, jint dst_height, jobject params) { ALOGV("getFrameAtTime: %lld us option: %d dst width: %d heigh: %d", (long long)timeUs, option, dst_width, dst_height); @@ -392,10 +394,13 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime( jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return NULL; } + // For getFrameAtTime family of calls, default to HAL_PIXEL_FORMAT_RGB_565 + // to keep the behavior consistent with older releases + int colorFormat = getColorFormat(env, params, HAL_PIXEL_FORMAT_RGB_565); // Call native method to retrieve a video frame VideoFrame *videoFrame = NULL; - sp<IMemory> frameMemory = retriever->getFrameAtTime(timeUs, option); + sp<IMemory> frameMemory = retriever->getFrameAtTime(timeUs, option, colorFormat); // TODO: Using unsecurePointer() has some associated security pitfalls // (see declaration for details). // Either document why it is safe in this case or address the @@ -408,7 +413,9 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime( return NULL; } - return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, kRGB_565_SkColorType); + SkColorType outColorType = setOutColorType(env, colorFormat, params); + + return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, outColorType); } static jobject android_media_MediaMetadataRetriever_getImageAtIndex( @@ -739,7 +746,7 @@ static const JNINativeMethod nativeMethods[] = { (void *)android_media_MediaMetadataRetriever_setDataSourceFD}, {"_setDataSource", "(Landroid/media/MediaDataSource;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceCallback}, - {"_getFrameAtTime", "(JIII)Landroid/graphics/Bitmap;", + {"_getFrameAtTime", "(JIIILandroid/media/MediaMetadataRetriever$BitmapParams;)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime}, { "_getImageAtIndex", |