Add BitmapParams option to getFrameAtTime/getScaledFrameAtTime
Add versions of these two methods that accepts BitmapParams. Does not change spec or behavior of existing getFrameAtTime/ getScaledFrameAtTime. bug: 135718180 bug: 138114267 test: CTS MediaMetadataRetrieverTest; manual testing with thumbnails saved to storage and examine the outputs. Change-Id: I75e96dde072c94ac950f0be637cdd096e7543f10
This commit is contained in:
@@ -25383,6 +25383,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);
|
||||
@@ -25392,6 +25393,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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user