Merge "media: Add scaled video thumbnail extractor api." into oc-mr1-dev

am: 26a4940296

Change-Id: Ibfa5394a612dcec663b1d8b4a301f94b1f2fb49e
This commit is contained in:
Hangyu Kuang
2017-08-02 19:22:36 +00:00
committed by android-build-merger
5 changed files with 89 additions and 26 deletions

View File

@@ -22742,6 +22742,7 @@ package android.media {
method public android.graphics.Bitmap getFrameAtTime(long, int);
method public android.graphics.Bitmap getFrameAtTime(long);
method public android.graphics.Bitmap getFrameAtTime();
method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
method public void release();
method public void setDataSource(java.lang.String) throws java.lang.IllegalArgumentException;
method public void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.lang.IllegalArgumentException;

View File

@@ -24686,6 +24686,7 @@ package android.media {
method public android.graphics.Bitmap getFrameAtTime(long, int);
method public android.graphics.Bitmap getFrameAtTime(long);
method public android.graphics.Bitmap getFrameAtTime();
method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
method public void release();
method public void setDataSource(java.lang.String) throws java.lang.IllegalArgumentException;
method public void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.lang.IllegalArgumentException;

View File

@@ -22878,6 +22878,7 @@ package android.media {
method public android.graphics.Bitmap getFrameAtTime(long, int);
method public android.graphics.Bitmap getFrameAtTime(long);
method public android.graphics.Bitmap getFrameAtTime();
method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
method public void release();
method public void setDataSource(java.lang.String) throws java.lang.IllegalArgumentException;
method public void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.lang.IllegalArgumentException;

View File

@@ -246,7 +246,7 @@ public class MediaMetadataRetriever
* {@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
* @return A Bitmap containing a representative video frame, which
* can be null, if such a frame cannot be retrieved.
*/
public Bitmap getFrameAtTime(long timeUs, int option) {
@@ -255,7 +255,58 @@ public class MediaMetadataRetriever
throw new IllegalArgumentException("Unsupported option: " + option);
}
return _getFrameAtTime(timeUs, option);
return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/);
}
/**
* Retrieve a video frame near a given timestamp scaled to a desired size.
* 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 with same aspect ratio as the source
* while scaling it so that it fits into the desired size of dst_width by dst_height.
* This is useful for generating a thumbnail for an input data source or just to
* obtain a scaled frame at the given time position.
*
* @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 dst_width expected output bitmap width
* @param dst_height expected output bitmap height
* @return A Bitmap of size not larger than dst_width by dst_height 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.
*/
public Bitmap getScaledFrameAtTime(
long timeUs, int option, int dst_width, int dst_height) {
if (option < OPTION_PREVIOUS_SYNC ||
option > OPTION_CLOSEST) {
throw new IllegalArgumentException("Unsupported option: " + option);
}
if (dst_width <= 0) {
throw new IllegalArgumentException("Invalid width: " + dst_width);
}
if (dst_height <= 0) {
throw new IllegalArgumentException("Invalid height: " + dst_height);
}
return _getFrameAtTime(timeUs, option, dst_width, dst_height);
}
/**
@@ -273,8 +324,8 @@ public class MediaMetadataRetriever
* negative, time position and option will ignored, and any frame
* that the implementation considers as representative may be returned.
*
* @return A Bitmap containing a representative video frame, which
* can be null, if such a frame cannot be retrieved.
* @return A Bitmap of size dst_widthxdst_height containing a representative
* video frame, which can be null, if such a frame cannot be retrieved.
*
* @see #getFrameAtTime(long, int)
*/
@@ -297,17 +348,16 @@ public class MediaMetadataRetriever
* @see #getFrameAtTime(long, int)
*/
public Bitmap getFrameAtTime() {
return getFrameAtTime(-1, OPTION_CLOSEST_SYNC);
return _getFrameAtTime(-1, OPTION_CLOSEST_SYNC, -1 /*dst_width*/, -1 /*dst_height*/);
}
private native Bitmap _getFrameAtTime(long timeUs, int option);
private native Bitmap _getFrameAtTime(long timeUs, int option, int width, int height);
/**
* Call this method after setDataSource(). This method finds the optional
* graphic or album/cover art associated associated with the data source. If
* there are more than one pictures, (any) one of them is returned.
*
*
* @return null if no such graphic is found.
*/
public byte[] getEmbeddedPicture() {

View File

@@ -244,9 +244,11 @@ static void rotate(T *dst, const T *src, size_t width, size_t height, int angle)
}
}
static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, jobject thiz, jlong timeUs, jint option)
static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
JNIEnv *env, jobject thiz, jlong timeUs, jint option, jint dst_width, jint dst_height)
{
ALOGV("getFrameAtTime: %lld us option: %d", (long long)timeUs, option);
ALOGV("getFrameAtTime: %lld us option: %d dst width: %d heigh: %d",
(long long)timeUs, option, dst_width, dst_height);
MediaMetadataRetriever* retriever = getRetriever(env, thiz);
if (retriever == 0) {
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
@@ -274,15 +276,19 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env,
fields.createConfigMethod,
GraphicsJNI::colorTypeToLegacyBitmapConfig(kRGB_565_SkColorType));
uint32_t width, height;
uint32_t width, height, displayWidth, displayHeight;
bool swapWidthAndHeight = false;
if (videoFrame->mRotationAngle == 90 || videoFrame->mRotationAngle == 270) {
width = videoFrame->mHeight;
height = videoFrame->mWidth;
swapWidthAndHeight = true;
displayWidth = videoFrame->mDisplayHeight;
displayHeight = videoFrame->mDisplayWidth;
} else {
width = videoFrame->mWidth;
height = videoFrame->mHeight;
displayWidth = videoFrame->mDisplayWidth;
displayHeight = videoFrame->mDisplayHeight;
}
jobject jBitmap = env->CallStaticObjectMethod(
@@ -308,22 +314,26 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env,
videoFrame->mHeight,
videoFrame->mRotationAngle);
if (videoFrame->mDisplayWidth != videoFrame->mWidth ||
videoFrame->mDisplayHeight != videoFrame->mHeight) {
uint32_t displayWidth = videoFrame->mDisplayWidth;
uint32_t displayHeight = videoFrame->mDisplayHeight;
if (swapWidthAndHeight) {
displayWidth = videoFrame->mDisplayHeight;
displayHeight = videoFrame->mDisplayWidth;
}
if (dst_width <= 0 || dst_height <= 0) {
dst_width = displayWidth;
dst_height = displayHeight;
} else {
float factor = std::min((float)dst_width / (float)displayWidth,
(float)dst_height / (float)displayHeight);
dst_width = std::round(displayWidth * factor);
dst_height = std::round(displayHeight * factor);
}
if ((uint32_t)dst_width != videoFrame->mWidth ||
(uint32_t)dst_height != videoFrame->mHeight) {
ALOGV("Bitmap dimension is scaled from %dx%d to %dx%d",
width, height, displayWidth, displayHeight);
width, height, dst_width, dst_height);
jobject scaledBitmap = env->CallStaticObjectMethod(fields.bitmapClazz,
fields.createScaledBitmapMethod,
jBitmap,
displayWidth,
displayHeight,
true);
fields.createScaledBitmapMethod,
jBitmap,
dst_width,
dst_height,
true);
return scaledBitmap;
}
@@ -474,7 +484,7 @@ static const JNINativeMethod nativeMethods[] = {
{"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
{"_setDataSource", "(Landroid/media/MediaDataSource;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceCallback},
{"_getFrameAtTime", "(JI)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
{"_getFrameAtTime", "(JIII)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
{"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},
{"getEmbeddedPicture", "(I)[B", (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture},
{"release", "()V", (void *)android_media_MediaMetadataRetriever_release},