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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user