diff options
author | 2023-04-12 17:37:36 +0000 | |
---|---|---|
committer | 2023-04-21 06:48:18 +0000 | |
commit | fff1a293e380ed87258f741475574eb37f77fe4f (patch) | |
tree | b58c8f6c1a2935e2e101f47d942bb8c3b905b951 | |
parent | 50ab78c23458fb8ae2a2e8547306ab8add99ba48 (diff) |
Fallback to RGBA_8888 when P010 is not supported
It's possible that a TV does not support P010, which means
the TV is not able to decode 10-bit HEIF to RGBA_1010102.
In this case, falling back to output RGBA_8888 is necessary.
Bug: 276879147
Test: atest BitmapFactory#testDecode10BitHEIF10BitBitmap
atest ImageDecoderTest#testDecode10BitHeif
Change-Id: I33f7f30cbee0080dc81764c73428dcac3c75ce88
-rw-r--r-- | graphics/java/android/graphics/ImageDecoder.java | 41 | ||||
-rw-r--r-- | libs/hwui/jni/BitmapFactory.cpp | 8 | ||||
-rw-r--r-- | libs/hwui/jni/BitmapFactory.h | 6 | ||||
-rw-r--r-- | libs/hwui/jni/ImageDecoder.cpp | 14 |
4 files changed, 56 insertions, 13 deletions
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 56c3068fe5e9..302c72ead52e 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -42,7 +42,6 @@ import android.media.MediaCodecInfo; import android.media.MediaCodecList; import android.net.Uri; import android.os.Build; -import android.os.SystemProperties; import android.os.Trace; import android.system.ErrnoException; import android.system.Os; @@ -2069,47 +2068,67 @@ public final class ImageDecoder implements AutoCloseable { } private static boolean sIsP010SupportedForAV1 = false; - private static boolean sIsP010SupportedForAV1Initialized = false; - private static final Object sIsP010SupportedForAV1Lock = new Object(); + private static boolean sIsP010SupportedForHEVC = false; + private static boolean sIsP010SupportedFlagsInitialized = false; + private static final Object sIsP010SupportedLock = new Object(); /** * Checks if the device supports decoding 10-bit AV1. */ @SuppressWarnings("AndroidFrameworkCompatChange") // This is not an app-visible API. private static boolean isP010SupportedForAV1() { - synchronized (sIsP010SupportedForAV1Lock) { - if (sIsP010SupportedForAV1Initialized) { + synchronized (sIsP010SupportedLock) { + if (sIsP010SupportedFlagsInitialized) { return sIsP010SupportedForAV1; } + checkP010SupportforAV1HEVC(); + return sIsP010SupportedForAV1; + } + } - sIsP010SupportedForAV1Initialized = true; - return sIsP010SupportedForAV1 = isP010SupportedforMime("video/av01"); + /** + * Checks if the device supports decoding 10-bit HEVC. + * This method is called by JNI. + */ + @SuppressWarnings("unused") + private static boolean isP010SupportedForHEVC() { + synchronized (sIsP010SupportedLock) { + if (sIsP010SupportedFlagsInitialized) { + return sIsP010SupportedForHEVC; + } + checkP010SupportforAV1HEVC(); + return sIsP010SupportedForHEVC; } } /** * Checks if the device supports decoding 10-bit for the given mime type. */ - private static boolean isP010SupportedforMime(String mime) { + private static void checkP010SupportforAV1HEVC() { MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS); for (MediaCodecInfo mediaCodecInfo : codecList.getCodecInfos()) { if (mediaCodecInfo.isEncoder()) { continue; } for (String mediaType : mediaCodecInfo.getSupportedTypes()) { - if (mediaType.equalsIgnoreCase(mime)) { + if (mediaType.equalsIgnoreCase("video/av01") + || mediaType.equalsIgnoreCase("video/hevc")) { MediaCodecInfo.CodecCapabilities codecCapabilities = mediaCodecInfo.getCapabilitiesForType(mediaType); for (int i = 0; i < codecCapabilities.colorFormats.length; ++i) { if (codecCapabilities.colorFormats[i] == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010) { - return true; + if (mediaType.equalsIgnoreCase("video/av01")) { + sIsP010SupportedForAV1 = true; + } else { + sIsP010SupportedForHEVC = true; + } } } } } } - return false; + sIsP010SupportedFlagsInitialized = true; } /** diff --git a/libs/hwui/jni/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp index c57e6f09347a..38d17de166e9 100644 --- a/libs/hwui/jni/BitmapFactory.cpp +++ b/libs/hwui/jni/BitmapFactory.cpp @@ -401,6 +401,14 @@ static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream, decodeColorType = kN32_SkColorType; } + // b/276879147, fallback to RGBA_8888 when decoding HEIF and P010 is not supported. + if (decodeColorType == kRGBA_1010102_SkColorType && + codec->getEncodedFormat() == SkEncodedImageFormat::kHEIF && + env->CallStaticBooleanMethod(gImageDecoder_class, + gImageDecoder_isP010SupportedForHEVCMethodID) == JNI_FALSE) { + decodeColorType = kN32_SkColorType; + } + sk_sp<SkColorSpace> decodeColorSpace = codec->computeOutputColorSpace( decodeColorType, prefColorSpace); diff --git a/libs/hwui/jni/BitmapFactory.h b/libs/hwui/jni/BitmapFactory.h index 45bffc44967d..a079cb4b513d 100644 --- a/libs/hwui/jni/BitmapFactory.h +++ b/libs/hwui/jni/BitmapFactory.h @@ -1,8 +1,9 @@ #ifndef _ANDROID_GRAPHICS_BITMAP_FACTORY_H_ #define _ANDROID_GRAPHICS_BITMAP_FACTORY_H_ +#include <SkEncodedImageFormat.h> + #include "GraphicsJNI.h" -#include "SkEncodedImageFormat.h" extern jclass gOptions_class; extern jfieldID gOptions_justBoundsFieldID; @@ -26,6 +27,9 @@ extern jfieldID gOptions_bitmapFieldID; extern jclass gBitmapConfig_class; extern jmethodID gBitmapConfig_nativeToConfigMethodID; +extern jclass gImageDecoder_class; +extern jmethodID gImageDecoder_isP010SupportedForHEVCMethodID; + jstring getMimeTypeAsJavaString(JNIEnv*, SkEncodedImageFormat); #endif // _ANDROID_GRAPHICS_BITMAP_FACTORY_H_ diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp index db1c188e425e..6744c6c0b9ec 100644 --- a/libs/hwui/jni/ImageDecoder.cpp +++ b/libs/hwui/jni/ImageDecoder.cpp @@ -25,6 +25,7 @@ #include <SkCodecAnimation.h> #include <SkColorSpace.h> #include <SkColorType.h> +#include <SkEncodedImageFormat.h> #include <SkImageInfo.h> #include <SkRect.h> #include <SkSize.h> @@ -48,7 +49,8 @@ using namespace android; -static jclass gImageDecoder_class; +jclass gImageDecoder_class; +jmethodID gImageDecoder_isP010SupportedForHEVCMethodID; static jclass gSize_class; static jclass gDecodeException_class; static jclass gCanvas_class; @@ -298,6 +300,14 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong colorType = kN32_SkColorType; } + // b/276879147, fallback to RGBA_8888 when decoding HEIF and P010 is not supported. + if (colorType == kRGBA_1010102_SkColorType && + decoder->mCodec->getEncodedFormat() == SkEncodedImageFormat::kHEIF && + env->CallStaticBooleanMethod(gImageDecoder_class, + gImageDecoder_isP010SupportedForHEVCMethodID) == JNI_FALSE) { + colorType = kN32_SkColorType; + } + if (!decoder->setOutColorType(colorType)) { doThrowISE(env, "Failed to set out color type!"); return nullptr; @@ -540,6 +550,8 @@ int register_android_graphics_ImageDecoder(JNIEnv* env) { gImageDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder")); gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JIIZZ)V"); gImageDecoder_postProcessMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "postProcessAndRelease", "(Landroid/graphics/Canvas;)I"); + gImageDecoder_isP010SupportedForHEVCMethodID = + GetStaticMethodIDOrDie(env, gImageDecoder_class, "isP010SupportedForHEVC", "()Z"); gSize_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/util/Size")); gSize_constructorMethodID = GetMethodIDOrDie(env, gSize_class, "<init>", "(II)V"); |