Loading api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -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; api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -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; api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -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; media/java/android/media/MediaMetadataRetriever.java +58 −8 Original line number Diff line number Diff line Loading @@ -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); } /** Loading @@ -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) */ Loading @@ -297,11 +348,10 @@ 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 Loading media/jni/android_media_MediaMetadataRetriever.cpp +28 −18 Original line number Diff line number Diff line Loading @@ -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"); Loading Loading @@ -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( Loading @@ -308,21 +314,25 @@ 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, dst_width, dst_height, true); return scaledBitmap; } Loading Loading @@ -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}, Loading Loading
api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -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;
api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -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;
api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -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;
media/java/android/media/MediaMetadataRetriever.java +58 −8 Original line number Diff line number Diff line Loading @@ -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); } /** Loading @@ -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) */ Loading @@ -297,11 +348,10 @@ 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 Loading
media/jni/android_media_MediaMetadataRetriever.cpp +28 −18 Original line number Diff line number Diff line Loading @@ -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"); Loading Loading @@ -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( Loading @@ -308,21 +314,25 @@ 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, dst_width, dst_height, true); return scaledBitmap; } Loading Loading @@ -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}, Loading