diff --git a/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java b/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java index b6e6a4bc..9bb3f1c6 100644 --- a/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java +++ b/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java @@ -178,7 +178,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C return caps.areSizeAndRateSupported(prefs.width, prefs.height, prefs.fps); } - private boolean decoderCanMeetPerformancePointWithHevcAndNotAvc(MediaCodecInfo avcDecoderInfo, MediaCodecInfo hevcDecoderInfo, PreferenceConfiguration prefs) { + private boolean decoderCanMeetPerformancePointWithHevcAndNotAvc(MediaCodecInfo hevcDecoderInfo, MediaCodecInfo avcDecoderInfo, PreferenceConfiguration prefs) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { MediaCodecInfo.VideoCapabilities avcCaps = avcDecoderInfo.getCapabilitiesForType("video/avc").getVideoCapabilities(); MediaCodecInfo.VideoCapabilities hevcCaps = hevcDecoderInfo.getCapabilitiesForType("video/hevc").getVideoCapabilities(); @@ -191,6 +191,32 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C } } + private boolean decoderCanMeetPerformancePointWithAv1AndNotHevc(MediaCodecInfo av1DecoderInfo, MediaCodecInfo hevcDecoderInfo, PreferenceConfiguration prefs) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + MediaCodecInfo.VideoCapabilities av1Caps = av1DecoderInfo.getCapabilitiesForType("video/av01").getVideoCapabilities(); + MediaCodecInfo.VideoCapabilities hevcCaps = hevcDecoderInfo.getCapabilitiesForType("video/hevc").getVideoCapabilities(); + + return !decoderCanMeetPerformancePoint(hevcCaps, prefs) && decoderCanMeetPerformancePoint(av1Caps, prefs); + } + else { + // No performance data + return false; + } + } + + private boolean decoderCanMeetPerformancePointWithAv1AndNotAvc(MediaCodecInfo av1DecoderInfo, MediaCodecInfo avcDecoderInfo, PreferenceConfiguration prefs) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + MediaCodecInfo.VideoCapabilities avcCaps = avcDecoderInfo.getCapabilitiesForType("video/avc").getVideoCapabilities(); + MediaCodecInfo.VideoCapabilities av1Caps = av1DecoderInfo.getCapabilitiesForType("video/av01").getVideoCapabilities(); + + return !decoderCanMeetPerformancePoint(avcCaps, prefs) && decoderCanMeetPerformancePoint(av1Caps, prefs); + } + else { + // No performance data + return false; + } + } + private MediaCodecInfo findHevcDecoder(PreferenceConfiguration prefs, boolean meteredNetwork, boolean requestedHdr) { // Don't return anything if HEVC is forced off if (prefs.hevcFormat == PreferenceConfiguration.FormatOption.FORCE_OFF) { @@ -220,7 +246,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C LimeLog.info("Forcing HEVC enabled for over 4K streaming"); } // Use HEVC if the H.264 decoder is unable to meet the performance point - else if (avcDecoder != null && decoderCanMeetPerformancePointWithHevcAndNotAvc(avcDecoder, hevcDecoderInfo, prefs)) { + else if (avcDecoder != null && decoderCanMeetPerformancePointWithHevcAndNotAvc(hevcDecoderInfo, avcDecoder, prefs)) { LimeLog.info("Using non-whitelisted HEVC decoder to meet performance point"); } else { @@ -247,6 +273,14 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C if (prefs.av1Format == PreferenceConfiguration.FormatOption.FORCE_ON) { LimeLog.info("Forcing AV1 enabled despite non-whitelisted decoder"); } + // Use AV1 if the HEVC decoder is unable to meet the performance point + else if (hevcDecoder != null && decoderCanMeetPerformancePointWithAv1AndNotHevc(decoderInfo, hevcDecoder, prefs)) { + LimeLog.info("Using non-whitelisted AV1 decoder to meet performance point"); + } + // Use AV1 if the H.264 decoder is unable to meet the performance point and we have no HEVC decoder + else if (hevcDecoder == null && decoderCanMeetPerformancePointWithAv1AndNotAvc(decoderInfo, avcDecoder, prefs)) { + LimeLog.info("Using non-whitelisted AV1 decoder to meet performance point"); + } else { return null; } @@ -1487,7 +1521,10 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C // GFE 2.5.11 changed the SPS to add additional extensions. Some devices don't like these // so we remove them here on old devices unless these devices also support HEVC. // See getPreferredColorSpace() for further information. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O && hevcDecoder == null && sps.vuiParams != null) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O && + sps.vuiParams != null && + hevcDecoder == null && + av1Decoder == null) { sps.vuiParams.videoSignalTypePresentFlag = false; sps.vuiParams.colourDescriptionPresentFlag = false; sps.vuiParams.chromaLocInfoPresentFlag = false; @@ -1828,6 +1865,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C str += "Format: "+String.format("%x", renderer.videoFormat)+DELIMITER; str += "AVC Decoder: "+((renderer.avcDecoder != null) ? renderer.avcDecoder.getName():"(none)")+DELIMITER; str += "HEVC Decoder: "+((renderer.hevcDecoder != null) ? renderer.hevcDecoder.getName():"(none)")+DELIMITER; + str += "AV1 Decoder: "+((renderer.av1Decoder != null) ? renderer.av1Decoder.getName():"(none)")+DELIMITER; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && renderer.avcDecoder != null) { Range avcWidthRange = renderer.avcDecoder.getCapabilitiesForType("video/avc").getVideoCapabilities().getSupportedWidths(); str += "AVC supported width range: "+avcWidthRange+DELIMITER; @@ -1852,6 +1890,18 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C } } } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && renderer.av1Decoder != null) { + Range av1WidthRange = renderer.av1Decoder.getCapabilitiesForType("video/av01").getVideoCapabilities().getSupportedWidths(); + str += "AV1 supported width range: "+av1WidthRange+DELIMITER; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + try { + Range av1FpsRange = renderer.av1Decoder.getCapabilitiesForType("video/av01").getVideoCapabilities().getAchievableFrameRatesFor(renderer.initialWidth, renderer.initialHeight); + str += "AV1 achievable FPS range: " + av1FpsRange + DELIMITER; + } catch (IllegalArgumentException e) { + str += "AV1 achievable FPS range: UNSUPPORTED!"+DELIMITER; + } + } + } str += "Configured format: "+renderer.configuredFormat+DELIMITER; str += "Input format: "+renderer.inputFormat+DELIMITER; str += "Output format: "+renderer.outputFormat+DELIMITER;