diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 3253516d6c..55678c79ca 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -14,6 +14,8 @@ * Discard back buffer before playback gets stuck due to insufficient available memory. * Close the Tracing "doSomeWork" block when offload is enabled. + * Try alternative decoder for Dolby Vision if display does not support it. + ([#9794](https://github.com/google/ExoPlayer/issues/9794)). * Downloads: * Fix potential infinite loop in `ProgressiveDownloader` caused by simultaneous download and playback with the same `PriorityTaskManager` diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java index 968ba993e9..5d192aa4cd 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java @@ -15,6 +15,7 @@ */ package androidx.media3.exoplayer.video; +import static android.view.Display.DEFAULT_DISPLAY; import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED; import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_VIDEO_MAX_RESOLUTION_EXCEEDED; import static androidx.media3.exoplayer.DecoderReuseEvaluation.REUSE_RESULT_NO; @@ -25,6 +26,7 @@ import android.annotation.TargetApi; import android.content.Context; import android.graphics.Point; +import android.hardware.display.DisplayManager; import android.media.MediaCodec; import android.media.MediaCodecInfo.CodecCapabilities; import android.media.MediaCodecInfo.CodecProfileLevel; @@ -35,6 +37,7 @@ import android.os.Message; import android.os.SystemClock; import android.util.Pair; +import android.view.Display; import android.view.Surface; import androidx.annotation.CallSuper; import androidx.annotation.Nullable; @@ -356,6 +359,7 @@ public String getName() { boolean requiresSecureDecryption = drmInitData != null; List decoderInfos = getDecoderInfos( + context, mediaCodecSelector, format, requiresSecureDecryption, @@ -364,6 +368,7 @@ public String getName() { // No secure decoders are available. Fall back to non-secure decoders. decoderInfos = getDecoderInfos( + context, mediaCodecSelector, format, /* requiresSecureDecoder= */ false, @@ -411,6 +416,7 @@ public String getName() { if (isFormatSupported) { List tunnelingDecoderInfos = getDecoderInfos( + context, mediaCodecSelector, format, requiresSecureDecryption, @@ -439,7 +445,8 @@ protected List getDecoderInfos( MediaCodecSelector mediaCodecSelector, Format format, boolean requiresSecureDecoder) throws DecoderQueryException { return MediaCodecUtil.getDecoderInfosSortedByFormatSupport( - getDecoderInfos(mediaCodecSelector, format, requiresSecureDecoder, tunneling), format); + getDecoderInfos(context, mediaCodecSelector, format, requiresSecureDecoder, tunneling), + format); } /** @@ -459,6 +466,7 @@ protected List getDecoderInfos( * @throws DecoderQueryException Thrown if there was an error querying decoders. */ private static List getDecoderInfos( + Context context, MediaCodecSelector mediaCodecSelector, Format format, boolean requiresSecureDecoder, @@ -478,6 +486,28 @@ private static List getDecoderInfos( List alternativeDecoderInfos = mediaCodecSelector.getDecoderInfos( alternativeMimeType, requiresSecureDecoder, requiresTunnelingDecoder); + if (Util.SDK_INT >= 26 + && MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType) + && !alternativeDecoderInfos.isEmpty()) { + // If sample type is Dolby Vision, check if Display supports Dolby Vision + boolean supportsDolbyVision = false; + DisplayManager displayManager = + (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); + Display display = + (displayManager != null) ? displayManager.getDisplay(DEFAULT_DISPLAY) : null; + if (display != null && display.isHdr()) { + int[] supportedHdrTypes = display.getHdrCapabilities().getSupportedHdrTypes(); + for (int hdrType : supportedHdrTypes) { + if (hdrType == Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION) { + supportsDolbyVision = true; + break; + } + } + } + if (!supportsDolbyVision) { + return ImmutableList.copyOf(alternativeDecoderInfos); + } + } return ImmutableList.builder() .addAll(decoderInfos) .addAll(alternativeDecoderInfos)