Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26a49402 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

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

parents 7084e59b 0552036b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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;
+58 −8
Original line number Diff line number Diff line
@@ -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,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
+28 −18
Original line number Diff line number Diff line
@@ -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,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;
    }
@@ -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},