From dd425613b7edbcc27419a4cf23d4f3ccc46b8167 Mon Sep 17 00:00:00 2001 From: michaelkatz Date: Fri, 23 Sep 2022 13:43:21 +0000 Subject: [PATCH] Try alternative decoder for Dolby Vision if display does not support If the sample type is dolby vision and the following conditions match a)There is a supported alternative codec mimetype b)Display does not support Dolby Vision Then getDecoderInfos will return the alternative types. Issue: google/ExoPlayer#9794 PiperOrigin-RevId: 476356223 (cherry picked from commit ed79f4696f026872f2840c53f9526980f4c966d4) --- RELEASENOTES.md | 2 ++ .../video/MediaCodecVideoRenderer.java | 32 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) 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)