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

Commit b58417cc authored by Songyue Han's avatar Songyue Han
Browse files

Java and JNI support for native EncoderCapabilities.

Bug: b/306023029
Test: MediaCodecCapabilitiesTest
Change-Id: I39ba5949723a955f099c2111e6d55f2e4a8fac23
parent 5b11d4cc
Loading
Loading
Loading
Loading
+270 −164
Original line number Diff line number Diff line
@@ -4312,27 +4312,7 @@ public final class MediaCodecInfo {
     * A class that supports querying the encoding capabilities of a codec.
     */
    public static final class EncoderCapabilities {
        /**
         * Returns the supported range of quality values.
         *
         * Quality is implementation-specific. As a general rule, a higher quality
         * setting results in a better image quality and a lower compression ratio.
         */
        public Range<Integer> getQualityRange() {
            return mQualityRange;
        }

        /**
         * Returns the supported range of encoder complexity values.
         * <p>
         * Some codecs may support multiple complexity levels, where higher
         * complexity values use more encoder tools (e.g. perform more
         * intensive calculations) to improve the quality or the compression
         * ratio.  Use a lower value to save power and/or time.
         */
        public Range<Integer> getComplexityRange() {
            return mComplexityRange;
        }
        private static final String TAG = "EncoderCapabilities";

        /** Constant quality mode */
        public static final int BITRATE_MODE_CQ = 0;
@@ -4343,6 +4323,32 @@ public final class MediaCodecInfo {
        /** Constant bitrate mode with frame drops */
        public static final int BITRATE_MODE_CBR_FD =  3;

        /* package private */ interface EncoderCapsIntf {
            public Range<Integer> getQualityRange();

            public Range<Integer> getComplexityRange();

            public boolean isBitrateModeSupported(int mode);

            public void getDefaultFormat(MediaFormat format);

            public boolean supportsFormat(MediaFormat format);
        }

        /* package private */ static final class EncoderCapsLegacyImpl implements EncoderCapsIntf {
            private CodecCapabilities mParent;

            private Range<Integer> mQualityRange;
            private Range<Integer> mComplexityRange;

            public Range<Integer> getQualityRange() {
                return mQualityRange;
            }

            public Range<Integer> getComplexityRange() {
                return mComplexityRange;
            }

            private static final Feature[] bitrates = new Feature[] {
                new Feature("VBR", BITRATE_MODE_VBR, true),
                new Feature("CBR", BITRATE_MODE_CBR, false),
@@ -4359,9 +4365,6 @@ public final class MediaCodecInfo {
                return 0;
            }

        /**
         * Query whether a bitrate mode is supported.
         */
            public boolean isBitrateModeSupported(int mode) {
                for (Feature feat: bitrates) {
                    if (mode == feat.mValue) {
@@ -4371,17 +4374,17 @@ public final class MediaCodecInfo {
                return false;
            }

        private Range<Integer> mQualityRange;
        private Range<Integer> mComplexityRange;
        private CodecCapabilities mParent;

            /* no public constructor */
        private EncoderCapabilities() { }
            private EncoderCapsLegacyImpl() { }

            /** @hide */
        public static EncoderCapabilities create(
            public static EncoderCapsLegacyImpl create(
                    MediaFormat info, CodecCapabilities parent) {
            EncoderCapabilities caps = new EncoderCapabilities();
                if (GetFlag(() -> android.media.codec.Flags.nativeCapabilites())) {
                    Log.d(TAG, "Legacy implementation is called while native flag is on.");
                }

                EncoderCapsLegacyImpl caps = new EncoderCapsLegacyImpl();
                caps.init(info, parent);
                return caps;
            }
@@ -4526,6 +4529,109 @@ public final class MediaCodecInfo {

                return supports(complexity, quality, profile);
            }
        }

        /* package private */ static final class EncoderCapsNativeImpl implements EncoderCapsIntf {
            private long mNativeContext; // accessed by native methods

            private Range<Integer> mQualityRange;
            private Range<Integer> mComplexityRange;

            /* no public constructor */
            private EncoderCapsNativeImpl() { }

            // Constructor called from native
            /* package private */ EncoderCapsNativeImpl(Range<Integer> qualityRange,
                    Range<Integer> complexityRange) {
                mQualityRange = qualityRange;
                mComplexityRange = complexityRange;
            }

            public Range<Integer> getQualityRange() {
                return mQualityRange;
            }

            public Range<Integer> getComplexityRange() {
                return mComplexityRange;
            }

            public boolean isBitrateModeSupported(int mode) {
                return native_isBitrateModeSupported(mode);
            }

            // This API is for internal Java implementation only. Should not be called.
            public void getDefaultFormat(MediaFormat format) {
                throw new UnsupportedOperationException(
                    "Java Implementation should not call native implemenatation");
            }

            // This API is for internal Java implementation only. Should not be called.
            public boolean supportsFormat(MediaFormat format) {
                throw new UnsupportedOperationException(
                    "Java Implementation should not call native implemenatation");
            }

            private native boolean native_isBitrateModeSupported(int mode);
            private static native void native_init();

            static {
                System.loadLibrary("media_jni");
                native_init();
            }
        }

        private EncoderCapsIntf mImpl;

        /** @hide */
        public static EncoderCapabilities create(
                MediaFormat info, CodecCapabilities parent) {
            EncoderCapsLegacyImpl impl = EncoderCapsLegacyImpl.create(info, parent);
            EncoderCapabilities caps = new EncoderCapabilities(impl);
            return caps;
        }

        /* package private */ EncoderCapabilities(EncoderCapsIntf impl) {
            mImpl = impl;
        }

        /**
         * Returns the supported range of quality values.
         *
         * Quality is implementation-specific. As a general rule, a higher quality
         * setting results in a better image quality and a lower compression ratio.
         */
        public Range<Integer> getQualityRange() {
            return mImpl.getQualityRange();
        }

        /**
         * Returns the supported range of encoder complexity values.
         * <p>
         * Some codecs may support multiple complexity levels, where higher
         * complexity values use more encoder tools (e.g. perform more
         * intensive calculations) to improve the quality or the compression
         * ratio.  Use a lower value to save power and/or time.
         */
        public Range<Integer> getComplexityRange() {
            return mImpl.getComplexityRange();
        }

        /**
         * Query whether a bitrate mode is supported.
         */
        public boolean isBitrateModeSupported(int mode) {
            return mImpl.isBitrateModeSupported(mode);
        }

        /** @hide */
        public void getDefaultFormat(MediaFormat format) {
            mImpl.getDefaultFormat(format);
        }

        /** @hide */
        public boolean supportsFormat(MediaFormat format) {
            return mImpl.supportsFormat(format);
        }
    };

    /**
+49 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "jni.h"

#include <media/AudioCapabilities.h>
#include <media/EncoderCapabilities.h>
#include <media/VideoCapabilities.h>
#include <media/stagefright/foundation/ADebug.h>
#include <nativehelper/JNIHelp.h>
@@ -30,6 +31,7 @@ namespace android {
struct fields_t {
    jfieldID audioCapsContext;
    jfieldID videoCapsContext;
    jfieldID encoderCapsContext;
};
static fields_t fields;

@@ -47,6 +49,12 @@ static VideoCapabilities* getVideoCapabilities(JNIEnv *env, jobject thiz) {
    return p;
}

static EncoderCapabilities* getEncoderCapabilities(JNIEnv *env, jobject thiz) {
    EncoderCapabilities* const p = (EncoderCapabilities*)env->GetLongField(
            thiz, fields.encoderCapsContext);
    return p;
}

// Utils

static jobject convertToJavaIntRange(JNIEnv *env, const Range<int32_t>& range) {
@@ -305,6 +313,35 @@ static jint android_media_VideoCapabilities_getSmallerDimensionUpperLimit(JNIEnv
    return smallerDimensionUpperLimit;
}

// EncoderCapabilities

static void android_media_EncoderCapabilities_native_init(JNIEnv *env, jobject /* thiz */) {
    jclass clazz = env->FindClass(
            "android/media/MediaCodecInfo$EncoderCapabilities$EncoderCapsNativeImpl");
    if (clazz == NULL) {
        return;
    }

    fields.encoderCapsContext = env->GetFieldID(clazz, "mNativeContext", "J");
    if (fields.encoderCapsContext == NULL) {
        return;
    }

    env->DeleteLocalRef(clazz);
}

static jboolean android_media_EncoderCapabilities_isBitrateModeSupported(JNIEnv *env, jobject thiz,
        int mode) {
    EncoderCapabilities* const encoderCaps = getEncoderCapabilities(env, thiz);
    if (encoderCaps == nullptr) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return 0;
    }

    bool res = encoderCaps->isBitrateModeSupported(mode);
    return res;
}

// ----------------------------------------------------------------------------

static const JNINativeMethod gAudioCapsMethods[] = {
@@ -330,6 +367,11 @@ static const JNINativeMethod gVideoCapsMethods[] = {
    {"native_getSmallerDimensionUpperLimit", "()I", (void *)android_media_VideoCapabilities_getSmallerDimensionUpperLimit}
};

static const JNINativeMethod gEncoderCapsMethods[] = {
    {"native_init", "()V", (void *)android_media_EncoderCapabilities_native_init},
    {"native_isBitrateModeSupported", "(I)Z", (void *)android_media_EncoderCapabilities_isBitrateModeSupported}
};

int register_android_media_CodecCapabilities(JNIEnv *env) {
    int result = AndroidRuntime::registerNativeMethods(env,
            "android/media/MediaCodecInfo$AudioCapabilities$AudioCapsNativeImpl",
@@ -352,5 +394,12 @@ int register_android_media_CodecCapabilities(JNIEnv *env) {
        return result;
    }

    result = AndroidRuntime::registerNativeMethods(env,
            "android/media/MediaCodecInfo$EncoderCapabilities$EncoderCapsNativeImpl",
            gEncoderCapsMethods, NELEM(gEncoderCapsMethods));
    if (result != JNI_OK) {
        return result;
    }

    return result;
}
 No newline at end of file