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

Commit 989747ab authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes from topic "codec_availability_hal_api" into main

* changes:
  MediaCodec: define available and required resources test api
  media: add available/required resources test api
parents 4fe0c9b8 71d43ec8
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -2044,6 +2044,29 @@ package android.media {
    method public boolean isAidlHal();
  }

  public final class MediaCodec {
    method @FlaggedApi("android.media.codec.codec_availability") @NonNull public static java.util.List<android.media.MediaCodec.GlobalResourceInfo> getGloballyAvailableResources();
    method @FlaggedApi("android.media.codec.codec_availability") @NonNull public java.util.List<android.media.MediaCodec.InstanceResourceInfo> getRequiredResources();
  }

  public abstract static class MediaCodec.Callback {
    method @FlaggedApi("android.media.codec.codec_availability") public void onRequiredResourcesChanged(@NonNull android.media.MediaCodec);
  }

  @FlaggedApi("android.media.codec.codec_availability") public static final class MediaCodec.GlobalResourceInfo {
    ctor public MediaCodec.GlobalResourceInfo();
    method public long getAvailable();
    method public long getCapacity();
    method @NonNull public String getName();
  }

  @FlaggedApi("android.media.codec.codec_availability") public static final class MediaCodec.InstanceResourceInfo {
    ctor public MediaCodec.InstanceResourceInfo();
    method @NonNull public String getName();
    method public long getPerFrameCount();
    method public long getStaticCount();
  }

  public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
    ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int, int, @NonNull android.util.Size);
    ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint, @NonNull android.util.Size);
+165 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.media;

import static android.media.codec.Flags.FLAG_CODEC_AVAILABILITY;
import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
import static android.media.codec.Flags.FLAG_SUBSESSION_METRICS;
@@ -29,6 +30,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.ImageFormat;
import android.graphics.Rect;
@@ -1843,6 +1845,12 @@ final public class MediaCodec {
     */
    private static final int CB_METRICS_FLUSHED = 8;

    /**
     * Callback ID to notify the change in resource requirement
     * for the codec component.
     */
    private static final int CB_REQUIRED_RESOURCES_CHANGE = 9;

    private class EventHandler extends Handler {
        private MediaCodec mCodec;

@@ -2017,13 +2025,19 @@ final public class MediaCodec {

                case CB_METRICS_FLUSHED:
                {

                    if (GetFlag(() -> android.media.codec.Flags.subsessionMetrics())) {
                        mCallback.onMetricsFlushed(mCodec, (PersistableBundle)msg.obj);
                    }
                    break;
                }

                case CB_REQUIRED_RESOURCES_CHANGE: {
                    if (android.media.codec.Flags.codecAvailability()) {
                        mCallback.onRequiredResourcesChanged(mCodec);
                    }
                    break;
                }

                default:
                {
                    break;
@@ -2301,6 +2315,70 @@ final public class MediaCodec {
        }
    }

    /**
     * @hide
     * Abstraction for the Global Codec resources.
     * This encapsulates all the available codec resources on the device.
     *
     * To be able to enforce and test the implementation of codec availability hal APIs,
     * globally available codec resources are exposed only as TestApi.
     * This will be tracked and verified through cts.
     */
    @FlaggedApi(FLAG_CODEC_AVAILABILITY)
    @TestApi
    public static final class GlobalResourceInfo {
        /**
         * Identifier for the Resource type.
         */
        String mName;
        /**
         * Total count/capacity of resources of this type.
         */
        long mCapacity;
        /**
         * Available count of this resource type.
         */
        long mAvailable;

        @NonNull
        public String getName() {
            return mName;
        }

        public long getCapacity() {
            return mCapacity;
        }

        public long getAvailable() {
            return mAvailable;
        }
    };

    /**
     * @hide
     * Get a list of globally available codec resources.
     *
     * To be able to enforce and test the implementation of codec availability hal APIs,
     * it is exposed only as TestApi.
     * This will be tracked and verified through cts.
     *
     * This returns a {@link java.util.List} list of codec resources.
     * For every {@link GlobalResourceInfo} in the list, it encapsulates the
     * information about each resources available globaly on device.
     *
     * @return A list of available device codec resources; an empty list if no
     *         device codec resources are available.
     * @throws UnsupportedOperationException if not implemented.
     */
    @FlaggedApi(FLAG_CODEC_AVAILABILITY)
    @TestApi
    public static @NonNull List<GlobalResourceInfo> getGloballyAvailableResources() {
        return native_getGloballyAvailableResources();
    }

    @NonNull
    private static native List<GlobalResourceInfo> native_getGloballyAvailableResources();

    /**
     * Configures a component.
     *
@@ -2442,6 +2520,73 @@ final public class MediaCodec {
        }
    }

    /**
     * @hide
     * Abstraction for the resources associated with a codec instance.
     * This encapsulates the required codec resources for a configured codec instance.
     *
     * To be able to enforce and test the implementation of codec availability hal APIs,
     * required codec resources are exposed only as TestApi.
     * This will be tracked and verified through cts.
     */
    @FlaggedApi(FLAG_CODEC_AVAILABILITY)
    @TestApi
    public static final class InstanceResourceInfo {
        /**
         * Identifier for the Resource type.
         */
        String mName;
        /**
         * Required resource count of this type.
         */
        long mStaticCount;
        /**
         * Per frame resource requirement of this resource type.
         */
        long mPerFrameCount;

        @NonNull
        public String getName() {
            return mName;
        }

        public long getStaticCount() {
            return mStaticCount;
        }

        public long getPerFrameCount() {
            return mPerFrameCount;
        }
    };

    /**
     * @hide
     * Get a list of required codec resources for this configuration.
     *
     * To be able to enforce and test the implementation of codec availability hal APIs,
     * it is exposed only as TestApi.
     * This will be tracked and verified through cts.
     *
     * This returns a {@link java.util.List} list of codec resources.
     * For every {@link GlobalResourceInfo} in the list, it encapsulates the
     * information about each resources required for the current configuration.
     *
     * NOTE: This may only be called after {@link #configure}.
     *
     * @return A list of required device codec resources; an empty list if no
     *         device codec resources are required.
     * @throws IllegalStateException if the codec wasn't configured yet.
     * @throws UnsupportedOperationException if not implemented.
     */
    @FlaggedApi(FLAG_CODEC_AVAILABILITY)
    @TestApi
    public @NonNull List<InstanceResourceInfo> getRequiredResources() {
        return native_getRequiredResources();
    }

    @NonNull
    private native List<InstanceResourceInfo> native_getRequiredResources();

    /**
     *  Dynamically sets the output surface of a codec.
     *  <p>
@@ -5740,6 +5885,25 @@ final public class MediaCodec {
                @NonNull MediaCodec codec, @NonNull PersistableBundle metrics) {
            // default implementation ignores this callback.
        }

        /**
         * @hide
         * Called when there is a change in the required resources for the codec.
         * <p>
         * Upon receiving this notification, the updated resource requirement
         * can be queried through {@link #getRequiredResources}.
         *
         * @param codec The MediaCodec object.
         */
        @FlaggedApi(FLAG_CODEC_AVAILABILITY)
        @TestApi
        public void onRequiredResourcesChanged(@NonNull MediaCodec codec) {
            /*
             * A default implementation for backward compatibility.
             * Since this is a TestApi, we are not enforcing the callback to be
             * overridden.
             */
        }
    }

    private void postEventFromNative(
+1 −0
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ cc_library_shared {
        "libgrallocusage",
        "libmedia_midiiowrapper",
        "android.companion.virtualdevice.flags-aconfig-cc",
        "android.media.codec-aconfig-cc",
        "android.media.playback.flags-aconfig-cc",
    ],

+147 −0
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@
#include <C2Buffer.h>
#include <C2PlatformSupport.h>

#include <android_media_codec.h>

#include <android/hardware/cas/native/1.0/IDescrambler.h>

#include <android_runtime/android_hardware_HardwareBuffer.h>
@@ -189,6 +191,22 @@ static struct {
    jmethodID setId;
} gBufferInfo;

static struct {
    jclass clazz;
    jmethodID ctorId;
    jfieldID resourceId;
    jfieldID capacityId;
    jfieldID availableId;
} gGlobalResourceInfo;

static struct {
    jclass clazz;
    jmethodID ctorId;
    jfieldID resourceId;
    jfieldID staticCountId;
    jfieldID perFrameCountId;
} gInstanceResourceInfo;

struct fields_t {
    jmethodID postEventFromNativeID;
    jmethodID lockAndGetContextID;
@@ -1129,6 +1147,37 @@ status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject names
    return mCodec->unsubscribeFromVendorParameters(names);
}

static jobject getJavaResources(
        JNIEnv *env,
        const std::vector<MediaCodec::InstanceResourceInfo>& resources) {
    jobject resourcesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
    for (const MediaCodec::InstanceResourceInfo& res : resources) {
        ScopedLocalRef<jobject> object{env, env->NewObject(
                gInstanceResourceInfo.clazz, gInstanceResourceInfo.ctorId)};
        ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(res.mName.c_str())};
        env->SetObjectField(object.get(), gInstanceResourceInfo.resourceId, nameStr.get());
        env->SetLongField(object.get(),
                          gInstanceResourceInfo.staticCountId,
                          (jlong)res.mStaticCount);
        env->SetLongField(object.get(),
                          gInstanceResourceInfo.perFrameCountId,
                          (jlong)res.mPerFrameCount);
        (void)env->CallBooleanMethod(resourcesObj, gArrayListInfo.addId, object.get());
    }

    return resourcesObj;
}

status_t JMediaCodec::getRequiredResources(JNIEnv *env, jobject *resourcesObj) {
    std::vector<MediaCodec::InstanceResourceInfo> resources;
    status_t status = mCodec->getRequiredResources(resources);
    if (status != OK) {
        return status;
    }
    *resourcesObj = getJavaResources(env, resources);
    return OK;
}

static jthrowable createCodecException(
        JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
    ScopedLocalRef<jclass> clazz(
@@ -1475,6 +1524,10 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
            obj = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
            break;
        }
        case MediaCodec::CB_REQUIRED_RESOURCES_CHANGED:
        {
            break;
        }

        default:
            TRESPASS();
@@ -3560,6 +3613,64 @@ static void android_media_MediaCodec_unsubscribeFromVendorParameters(
    return;
}

static jobject getJavaResources(
        JNIEnv *env,
        const std::vector<MediaCodec::GlobalResourceInfo>& resources) {
    jobject resourcesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
    for (const MediaCodec::GlobalResourceInfo& res : resources) {
        ScopedLocalRef<jobject> object{env, env->NewObject(
                gGlobalResourceInfo.clazz, gGlobalResourceInfo.ctorId)};
        ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(res.mName.c_str())};
        env->SetObjectField(object.get(), gInstanceResourceInfo.resourceId, nameStr.get());
        env->SetLongField(object.get(), gGlobalResourceInfo.capacityId, (jlong)res.mCapacity);
        env->SetLongField(object.get(), gGlobalResourceInfo.availableId, (jlong)res.mAvailable);
        (void)env->CallBooleanMethod(resourcesObj, gArrayListInfo.addId, object.get());
    }

    return resourcesObj;
}

static jobject android_media_MediaCodec_getGloballyAvailableResources(
        JNIEnv *env, jobject thiz) {
    (void)thiz;
    std::vector<MediaCodec::GlobalResourceInfo> resources;
    status_t status = MediaCodec::getGloballyAvailableResources(resources);
    if (status != OK) {
        if (status == ERROR_UNSUPPORTED) {
            jniThrowException(env, "java/lang/UnsupportedOperationException",
                              "Function Not Implemented");
        } else {
            throwExceptionAsNecessary(env, status, nullptr);
        }
        return nullptr;
    }

    return getJavaResources(env, resources);
}

static jobject android_media_MediaCodec_getRequiredResources(
        JNIEnv *env, jobject thiz) {
    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
    if (codec == nullptr || codec->initCheck() != OK) {
        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
        return nullptr;
    }

    jobject ret = nullptr;
    status_t status = codec->getRequiredResources(env, &ret);
    if (status != OK) {
        if (status == ERROR_UNSUPPORTED) {
            jniThrowException(env, "java/lang/UnsupportedOperationException",
                              "Function Not Implemented");
        } else {
            throwExceptionAsNecessary(env, status, nullptr);
        }
        return nullptr;
    }

    return ret;
}

static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
    ScopedLocalRef<jclass> clazz(
            env, env->FindClass("android/media/MediaCodec"));
@@ -3905,6 +4016,36 @@ static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
    gFields.bufferInfoOffset = env->GetFieldID(clazz.get(), "offset", "I");
    gFields.bufferInfoPresentationTimeUs =
            env->GetFieldID(clazz.get(), "presentationTimeUs", "J");

    // Since these TestApis are defined under the flag, make sure they are
    // accessed only when the flag is set.
    if (android::media::codec::codec_availability()) {
        clazz.reset(env->FindClass("android/media/MediaCodec$GlobalResourceInfo"));
        CHECK(clazz.get() != NULL);
        gGlobalResourceInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
        gGlobalResourceInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
        CHECK(gGlobalResourceInfo.ctorId != NULL);
        gGlobalResourceInfo.resourceId =
                env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
        CHECK(gGlobalResourceInfo.resourceId != NULL);
        gGlobalResourceInfo.capacityId = env->GetFieldID(clazz.get(), "mCapacity", "J");
        CHECK(gGlobalResourceInfo.capacityId != NULL);
        gGlobalResourceInfo.availableId = env->GetFieldID(clazz.get(), "mAvailable", "J");
        CHECK(gGlobalResourceInfo.availableId != NULL);

        clazz.reset(env->FindClass("android/media/MediaCodec$InstanceResourceInfo"));
        CHECK(clazz.get() != NULL);
        gInstanceResourceInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
        gInstanceResourceInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
        CHECK(gInstanceResourceInfo.ctorId != NULL);
        gInstanceResourceInfo.resourceId =
                env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
        CHECK(gInstanceResourceInfo.resourceId != NULL);
        gInstanceResourceInfo.staticCountId= env->GetFieldID(clazz.get(), "mStaticCount", "J");
        CHECK(gInstanceResourceInfo.staticCountId != NULL);
        gInstanceResourceInfo.perFrameCountId = env->GetFieldID(clazz.get(), "mPerFrameCount", "J");
        CHECK(gInstanceResourceInfo.perFrameCountId != NULL);
    }
}

static void android_media_MediaCodec_native_setup(
@@ -4261,6 +4402,12 @@ static const JNINativeMethod gMethods[] = {

    { "native_finalize", "()V",
      (void *)android_media_MediaCodec_native_finalize },

    { "native_getGloballyAvailableResources", "()Ljava/util/List;",
      (void *)android_media_MediaCodec_getGloballyAvailableResources},

    { "native_getRequiredResources", "()Ljava/util/List;",
      (void *)android_media_MediaCodec_getRequiredResources},
};

static const JNINativeMethod gLinearBlockMethods[] = {
+2 −0
Original line number Diff line number Diff line
@@ -185,6 +185,8 @@ struct JMediaCodec : public AHandler {

    status_t unsubscribeFromVendorParameters(JNIEnv *env, jobject names);

    status_t getRequiredResources(JNIEnv *env, jobject *resourcesObj);

    bool hasCryptoOrDescrambler() { return mHasCryptoOrDescrambler; }

    const sp<ICrypto> &getCrypto() { return mCrypto; }