Merge "Add BitmapParams option to getFrameAtTime/getScaledFrameAtTime"

This commit is contained in:
TreeHugger Robot
2019-10-09 18:17:26 +00:00
committed by Android (Google) Code Review
3 changed files with 115 additions and 16 deletions

View File

@@ -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;

View File

@@ -226,6 +226,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
@@ -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;

View File

@@ -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",