From 3f4648538289905168ceecdc06c5b7af72a64130 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 12 Dec 2015 21:11:08 -0800 Subject: [PATCH] Add support for streaming H.265 from Maxwell 2 cards --- app/libs/limelight-common.jar | Bin 1017826 -> 1020207 bytes app/src/main/java/com/limelight/Game.java | 20 +- .../video/AndroidCpuDecoderRenderer.java | 11 +- .../video/ConfigurableDecoderRenderer.java | 18 +- .../video/EnhancedDecoderRenderer.java | 2 +- .../video/MediaCodecDecoderRenderer.java | 183 +++++++++++++----- .../binding/video/MediaCodecHelper.java | 60 +++--- .../preferences/PreferenceConfiguration.java | 28 ++- app/src/main/res/values/arrays.xml | 11 ++ app/src/main/res/values/strings.xml | 3 + app/src/main/res/xml/preferences.xml | 7 + 11 files changed, 258 insertions(+), 85 deletions(-) diff --git a/app/libs/limelight-common.jar b/app/libs/limelight-common.jar index e7d0030c0de233ae107e74f99f56e978afa00c5c..6f656bf4082935ef92bc1d5c5f7fb49e90a7d43b 100644 GIT binary patch delta 39101 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 PVG{T-m}nvx4VeD}WyQuK delta 36867 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 diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 759a5be6..50a10a1e 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -208,7 +208,12 @@ public class Game extends Activity implements SurfaceHolder.Callback, } decoderRenderer = new ConfigurableDecoderRenderer(); - decoderRenderer.initializeWithFlags(drFlags); + decoderRenderer.initializeWithFlags(drFlags, prefConfig.videoFormat); + + // Display a message to the user if H.265 was forced on but we still didn't find a decoder + if (prefConfig.videoFormat == PreferenceConfiguration.FORCE_H265_ON && !decoderRenderer.isHevcSupported()) { + Toast.makeText(this, "No H.265 decoder found. Falling back to H.264", Toast.LENGTH_LONG).show(); + } StreamConfiguration config = new StreamConfiguration.Builder() .setResolution(prefConfig.width, prefConfig.height) @@ -221,6 +226,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, .enableLocalAudioPlayback(prefConfig.playHostAudio) .setMaxPacketSize(remote ? 1024 : 1292) .setRemote(remote) + .setHevcSupported(decoderRenderer.isHevcSupported()) .setAudioConfiguration(prefConfig.enable51Surround ? StreamConfiguration.AUDIO_CONFIGURATION_5_1 : StreamConfiguration.AUDIO_CONFIGURATION_STEREO) @@ -352,6 +358,8 @@ public class Game extends Activity implements SurfaceHolder.Callback, unbindService(usbDriverServiceConnection); } + VideoDecoderRenderer.VideoFormat videoFormat = conn.getActiveVideoFormat(); + displayedFailureDialog = true; stopConnection(); @@ -368,6 +376,16 @@ public class Game extends Activity implements SurfaceHolder.Callback, message = getResources().getString(R.string.conn_hardware_latency)+" "+averageDecoderLat+" ms"; } + // Add the video codec to the post-stream toast + if (message != null && videoFormat != VideoDecoderRenderer.VideoFormat.Unknown) { + if (videoFormat == VideoDecoderRenderer.VideoFormat.H265) { + message += " [H.265]"; + } + else { + message += " [H.264]"; + } + } + if (message != null) { Toast.makeText(this, message, Toast.LENGTH_LONG).show(); } diff --git a/app/src/main/java/com/limelight/binding/video/AndroidCpuDecoderRenderer.java b/app/src/main/java/com/limelight/binding/video/AndroidCpuDecoderRenderer.java index b682e233..258003b2 100644 --- a/app/src/main/java/com/limelight/binding/video/AndroidCpuDecoderRenderer.java +++ b/app/src/main/java/com/limelight/binding/video/AndroidCpuDecoderRenderer.java @@ -91,9 +91,14 @@ public class AndroidCpuDecoderRenderer extends EnhancedDecoderRenderer { } @Override - public boolean setup(int width, int height, int redrawRate, Object renderTarget, int drFlags) { + public boolean setup(VideoFormat format, int width, int height, int redrawRate, Object renderTarget, int drFlags) { this.targetFps = redrawRate; + // We should never make it here with H265 + if (format != VideoFormat.H264) { + return false; + } + int perfLevel = LOW_PERF; //findOptimalPerformanceLevel(); int threadCount; @@ -283,7 +288,7 @@ public class AndroidCpuDecoderRenderer extends EnhancedDecoderRenderer { } @Override - public String getDecoderName() { - return "CPU decoding"; + public boolean isHevcSupported() { + return false; } } diff --git a/app/src/main/java/com/limelight/binding/video/ConfigurableDecoderRenderer.java b/app/src/main/java/com/limelight/binding/video/ConfigurableDecoderRenderer.java index f65830ed..526ec1d8 100644 --- a/app/src/main/java/com/limelight/binding/video/ConfigurableDecoderRenderer.java +++ b/app/src/main/java/com/limelight/binding/video/ConfigurableDecoderRenderer.java @@ -1,5 +1,7 @@ package com.limelight.binding.video; +import android.media.MediaCodecInfo; + import com.limelight.nvstream.av.DecodeUnit; import com.limelight.nvstream.av.video.VideoDecoderRenderer; import com.limelight.nvstream.av.video.VideoDepacketizer; @@ -16,18 +18,18 @@ public class ConfigurableDecoderRenderer extends EnhancedDecoderRenderer { } @Override - public boolean setup(int width, int height, int redrawRate, Object renderTarget, int drFlags) { + public boolean setup(VideoFormat format, int width, int height, int redrawRate, Object renderTarget, int drFlags) { if (decoderRenderer == null) { throw new IllegalStateException("ConfigurableDecoderRenderer not initialized"); } - return decoderRenderer.setup(width, height, redrawRate, renderTarget, drFlags); + return decoderRenderer.setup(format, width, height, redrawRate, renderTarget, drFlags); } - public void initializeWithFlags(int drFlags) { + public void initializeWithFlags(int drFlags, int videoFormat) { if ((drFlags & VideoDecoderRenderer.FLAG_FORCE_HARDWARE_DECODING) != 0 || ((drFlags & VideoDecoderRenderer.FLAG_FORCE_SOFTWARE_DECODING) == 0 && - MediaCodecHelper.findProbableSafeDecoder() != null)) { - decoderRenderer = new MediaCodecDecoderRenderer(); + MediaCodecHelper.findProbableSafeDecoder("video/avc", MediaCodecInfo.CodecProfileLevel.AVCProfileHigh) != null)) { + decoderRenderer = new MediaCodecDecoderRenderer(videoFormat); } else { decoderRenderer = new AndroidCpuDecoderRenderer(); @@ -82,12 +84,12 @@ public class ConfigurableDecoderRenderer extends EnhancedDecoderRenderer { } @Override - public String getDecoderName() { + public boolean isHevcSupported() { if (decoderRenderer != null) { - return decoderRenderer.getDecoderName(); + return decoderRenderer.isHevcSupported(); } else { - return null; + return false; } } } diff --git a/app/src/main/java/com/limelight/binding/video/EnhancedDecoderRenderer.java b/app/src/main/java/com/limelight/binding/video/EnhancedDecoderRenderer.java index 5343c381..98e77d29 100644 --- a/app/src/main/java/com/limelight/binding/video/EnhancedDecoderRenderer.java +++ b/app/src/main/java/com/limelight/binding/video/EnhancedDecoderRenderer.java @@ -3,5 +3,5 @@ package com.limelight.binding.video; import com.limelight.nvstream.av.video.VideoDecoderRenderer; public abstract class EnhancedDecoderRenderer extends VideoDecoderRenderer { - public abstract String getDecoderName(); + public abstract boolean isHevcSupported(); } 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 008493d0..65abadc6 100644 --- a/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java +++ b/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java @@ -13,6 +13,7 @@ import com.limelight.nvstream.av.ByteBufferDescriptor; import com.limelight.nvstream.av.DecodeUnit; import com.limelight.nvstream.av.video.VideoDecoderRenderer; import com.limelight.nvstream.av.video.VideoDepacketizer; +import com.limelight.preferences.PreferenceConfiguration; import android.media.MediaCodec; import android.media.MediaCodecInfo; @@ -27,13 +28,17 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer { // Used on versions < 5.0 private ByteBuffer[] legacyInputBuffers; + private String avcDecoderName; + private String hevcDecoderName; + private MediaCodec videoDecoder; private Thread rendererThread; - private final boolean needsSpsBitstreamFixup, isExynos4; + private boolean needsSpsBitstreamFixup, isExynos4; private VideoDepacketizer depacketizer; - private final boolean adaptivePlayback, directSubmit; - private final boolean constrainedHighProfile; + private boolean adaptivePlayback, directSubmit; + private boolean constrainedHighProfile; private int initialWidth, initialHeight; + private VideoFormat videoFormat; private boolean needsBaselineSpsHack; private SeqParameterSet savedSps; @@ -43,71 +48,141 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer { private long decoderTimeMs; private int totalFrames; - private String decoderName; private int numSpsIn; private int numPpsIn; + private int numVpsIn; private int numIframeIn; - public MediaCodecDecoderRenderer() { + private MediaCodecInfo findAvcDecoder() { + MediaCodecInfo decoder = MediaCodecHelper.findProbableSafeDecoder("video/avc", MediaCodecInfo.CodecProfileLevel.AVCProfileHigh); + if (decoder == null) { + decoder = MediaCodecHelper.findFirstDecoder("video/avc"); + } + return decoder; + } + + private MediaCodecInfo findHevcDecoder(int videoFormat) { + // Don't return anything if H.265 is forced off + if (videoFormat == PreferenceConfiguration.FORCE_H265_OFF) { + return null; + } + + // We don't try the first HEVC decoder. We'd rather fall back to hardware accelerated AVC instead + // + // We need HEVC Main profile, so we could pass that constant to findProbableSafeDecoder, however + // some decoders (at least Qualcomm's Snapdragon 805) don't properly report support + // for even required levels of HEVC. + MediaCodecInfo decoderInfo = MediaCodecHelper.findProbableSafeDecoder("video/hevc", -1); + if (decoderInfo != null) { + if (!MediaCodecHelper.decoderIsWhitelistedForHevc(decoderInfo.getName())) { + LimeLog.info("Found HEVC decoder, but it's not whitelisted - "+decoderInfo.getName()); + + if (videoFormat == PreferenceConfiguration.FORCE_H265_ON) { + LimeLog.info("Forcing H265 enabled despite non-whitelisted decoder"); + } + else { + return null; + } + } + } + + return decoderInfo; + } + + public MediaCodecDecoderRenderer(int videoFormat) { //dumpDecoders(); - MediaCodecInfo decoder = MediaCodecHelper.findProbableSafeDecoder(); - if (decoder == null) { - decoder = MediaCodecHelper.findFirstDecoder(); + MediaCodecInfo avcDecoder = findAvcDecoder(); + if (avcDecoder != null) { + avcDecoderName = avcDecoder.getName(); + LimeLog.info("Selected AVC decoder: "+avcDecoderName); } - if (decoder == null) { - // This case is handled later in setup() - needsSpsBitstreamFixup = isExynos4 = - adaptivePlayback = directSubmit = - constrainedHighProfile = false; - return; + else { + LimeLog.warning("No AVC decoder found"); } - decoderName = decoder.getName(); - - // Set decoder-specific attributes - directSubmit = MediaCodecHelper.decoderCanDirectSubmit(decoderName, decoder); - adaptivePlayback = MediaCodecHelper.decoderSupportsAdaptivePlayback(decoderName, decoder); - needsSpsBitstreamFixup = MediaCodecHelper.decoderNeedsSpsBitstreamRestrictions(decoderName, decoder); - needsBaselineSpsHack = MediaCodecHelper.decoderNeedsBaselineSpsHack(decoderName, decoder); - constrainedHighProfile = MediaCodecHelper.decoderNeedsConstrainedHighProfile(decoderName, decoder); - isExynos4 = MediaCodecHelper.isExynos4Device(); - if (needsSpsBitstreamFixup) { - LimeLog.info("Decoder "+decoderName+" needs SPS bitstream restrictions fixup"); + MediaCodecInfo hevcDecoder = findHevcDecoder(videoFormat); + if (hevcDecoder != null) { + hevcDecoderName = hevcDecoder.getName(); + LimeLog.info("Selected HEVC decoder: "+hevcDecoderName); } - if (needsBaselineSpsHack) { - LimeLog.info("Decoder "+decoderName+" needs baseline SPS hack"); - } - if (constrainedHighProfile) { - LimeLog.info("Decoder "+decoderName+" needs constrained high profile"); - } - if (isExynos4) { - LimeLog.info("Decoder "+decoderName+" is on Exynos 4"); - } - if (directSubmit) { - LimeLog.info("Decoder "+decoderName+" will use direct submit"); + else { + LimeLog.info("No HEVC decoder found"); } } @Override - public boolean setup(int width, int height, int redrawRate, Object renderTarget, int drFlags) { + public boolean isHevcSupported() { + return hevcDecoderName != null; + } + + @Override + public boolean setup(VideoDecoderRenderer.VideoFormat format, int width, int height, int redrawRate, Object renderTarget, int drFlags) { this.initialWidth = width; this.initialHeight = height; + this.videoFormat = format; - if (decoderName == null) { - LimeLog.severe("No available hardware decoder!"); + String mimeType; + String selectedDecoderName; + + if (videoFormat == VideoFormat.H264) { + mimeType = "video/avc"; + selectedDecoderName = avcDecoderName; + + if (avcDecoderName == null) { + LimeLog.severe("No available AVC decoder!"); + return false; + } + + // These fixups only apply to H264 decoders + needsSpsBitstreamFixup = MediaCodecHelper.decoderNeedsSpsBitstreamRestrictions(selectedDecoderName); + needsBaselineSpsHack = MediaCodecHelper.decoderNeedsBaselineSpsHack(selectedDecoderName); + constrainedHighProfile = MediaCodecHelper.decoderNeedsConstrainedHighProfile(selectedDecoderName); + isExynos4 = MediaCodecHelper.isExynos4Device(); + if (needsSpsBitstreamFixup) { + LimeLog.info("Decoder "+selectedDecoderName+" needs SPS bitstream restrictions fixup"); + } + if (needsBaselineSpsHack) { + LimeLog.info("Decoder "+selectedDecoderName+" needs baseline SPS hack"); + } + if (constrainedHighProfile) { + LimeLog.info("Decoder "+selectedDecoderName+" needs constrained high profile"); + } + if (isExynos4) { + LimeLog.info("Decoder "+selectedDecoderName+" is on Exynos 4"); + } + } + else if (videoFormat == VideoFormat.H265) { + mimeType = "video/hevc"; + selectedDecoderName = hevcDecoderName; + + if (hevcDecoderName == null) { + LimeLog.severe("No available HEVC decoder!"); + return false; + } + } + else { + // Unknown format return false; } + // Set decoder-specific attributes + directSubmit = MediaCodecHelper.decoderCanDirectSubmit(selectedDecoderName); + adaptivePlayback = MediaCodecHelper.decoderSupportsAdaptivePlayback(selectedDecoderName); + + if (directSubmit) { + LimeLog.info("Decoder "+selectedDecoderName+" will use direct submit"); + } + // Codecs have been known to throw all sorts of crazy runtime exceptions // due to implementation problems try { - videoDecoder = MediaCodec.createByCodecName(decoderName); + videoDecoder = MediaCodec.createByCodecName(selectedDecoderName); } catch (Exception e) { return false; } - MediaFormat videoFormat = MediaFormat.createVideoFormat("video/avc", width, height); + MediaFormat videoFormat = MediaFormat.createVideoFormat(mimeType, width, height); // Adaptive playback can also be enabled by the whitelist on pre-KitKat devices // so we don't fill these pre-KitKat @@ -119,7 +194,7 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer { videoDecoder.configure(videoFormat, ((SurfaceHolder)renderTarget).getSurface(), null, 0); videoDecoder.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT); - LimeLog.info("Using hardware decoding"); + LimeLog.info("Using codec "+selectedDecoderName+" for hardware decoding "+mimeType); return true; } @@ -483,6 +558,8 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer { if ((decodeUnitFlags & DecodeUnit.DU_FLAG_CODEC_CONFIG) != 0) { ByteBufferDescriptor header = decodeUnit.getBufferHead(); + + // H264 SPS if (header.data[header.offset+4] == 0x67) { numSpsIn++; @@ -585,6 +662,8 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer { depacketizer.freeDecodeUnit(decodeUnit); return; + + // H264 PPS } else if (header.data[header.offset+4] == 0x68) { numPpsIn++; @@ -596,6 +675,15 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer { needsSpsReplay = true; } } + else if (header.data[header.offset+4] == 0x40) { + numVpsIn++; + } + else if (header.data[header.offset+4] == 0x42) { + numSpsIn++; + } + else if (header.data[header.offset+4] == 0x44) { + numPpsIn++; + } } // Copy data from our buffer list into the input buffer @@ -674,11 +762,6 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer { return (int)(totalTimeMs / totalFrames); } - @Override - public String getDecoderName() { - return decoderName; - } - private void notifyDuReceived(DecodeUnit du) { long currentTime = MediaCodecHelper.getMonotonicMillis(); long delta = currentTime-du.getReceiveTimestamp(); @@ -731,9 +814,11 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer { public String toString() { String str = ""; - str += "Decoder: "+renderer.decoderName+"\n"; + str += "Format: "+renderer.videoFormat+"\n"; + str += "AVC Decoder: "+renderer.avcDecoderName+"\n"; + str += "HEVC Decoder: "+renderer.hevcDecoderName+"\n"; str += "Initial video dimensions: "+renderer.initialWidth+"x"+renderer.initialHeight+"\n"; - str += "In stats: "+renderer.numSpsIn+", "+renderer.numPpsIn+", "+renderer.numIframeIn+"\n"; + str += "In stats: "+renderer.numVpsIn+", "+renderer.numSpsIn+", "+renderer.numPpsIn+", "+renderer.numIframeIn+"\n"; str += "Total frames: "+renderer.totalFrames+"\n"; str += "Average end-to-end client latency: "+getAverageEndToEndLatency()+"ms\n"; str += "Average hardware decoder latency: "+getAverageDecoderLatency()+"ms\n"; diff --git a/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java b/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java index 6a9c444c..6617d230 100644 --- a/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java +++ b/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java @@ -28,6 +28,7 @@ public class MediaCodecHelper { private static final List baselineProfileHackPrefixes; private static final List directSubmitPrefixes; private static final List constrainedHighProfilePrefixes; + private static final List whitelistedHevcDecoders; static { directSubmitPrefixes = new LinkedList(); @@ -72,6 +73,12 @@ public class MediaCodecHelper { constrainedHighProfilePrefixes = new LinkedList(); constrainedHighProfilePrefixes.add("omx.intel"); + + whitelistedHevcDecoders = new LinkedList<>(); + whitelistedHevcDecoders.add("omx.exynos"); + whitelistedHevcDecoders.add("omx.qcom"); + whitelistedHevcDecoders.add("omx.nvidia"); + whitelistedHevcDecoders.add("omx.mtk"); } private static boolean isDecoderInList(List decoderList, String decoderName) { @@ -92,7 +99,7 @@ public class MediaCodecHelper { } @TargetApi(Build.VERSION_CODES.KITKAT) - public static boolean decoderSupportsAdaptivePlayback(String decoderName, MediaCodecInfo decoderInfo) { + public static boolean decoderSupportsAdaptivePlayback(String decoderName) { /* FIXME: Intel's decoder on Nexus Player forces the high latency path if adaptive playback is enabled so we'll keep it off for now, since we don't know whether other devices also do the same @@ -120,21 +127,25 @@ public class MediaCodecHelper { return false; } - public static boolean decoderNeedsConstrainedHighProfile(String decoderName, MediaCodecInfo decoderInfo) { + public static boolean decoderNeedsConstrainedHighProfile(String decoderName) { return isDecoderInList(constrainedHighProfilePrefixes, decoderName); } - public static boolean decoderCanDirectSubmit(String decoderName, MediaCodecInfo decoderInfo) { + public static boolean decoderCanDirectSubmit(String decoderName) { return isDecoderInList(directSubmitPrefixes, decoderName) && !isExynos4Device(); } - public static boolean decoderNeedsSpsBitstreamRestrictions(String decoderName, MediaCodecInfo decoderInfo) { + public static boolean decoderNeedsSpsBitstreamRestrictions(String decoderName) { return isDecoderInList(spsFixupBitstreamFixupDecoderPrefixes, decoderName); } - public static boolean decoderNeedsBaselineSpsHack(String decoderName, MediaCodecInfo decoderInfo) { + public static boolean decoderNeedsBaselineSpsHack(String decoderName) { return isDecoderInList(baselineProfileHackPrefixes, decoderName); } + + public static boolean decoderIsWhitelistedForHevc(String decoderName) { + return isDecoderInList(whitelistedHevcDecoders, decoderName); + } @SuppressWarnings("deprecation") @SuppressLint("NewApi") @@ -199,7 +210,7 @@ public class MediaCodecHelper { return null; } - public static MediaCodecInfo findFirstDecoder() { + public static MediaCodecInfo findFirstDecoder(String mimeType) { for (MediaCodecInfo codecInfo : getMediaCodecList()) { // Skip encoders if (codecInfo.isEncoder()) { @@ -212,9 +223,9 @@ public class MediaCodecHelper { continue; } - // Find a decoder that supports H.264 + // Find a decoder that supports the specified video format for (String mime : codecInfo.getSupportedTypes()) { - if (mime.equalsIgnoreCase("video/avc")) { + if (mime.equalsIgnoreCase(mimeType)) { LimeLog.info("First decoder choice is "+codecInfo.getName()); return codecInfo; } @@ -224,7 +235,7 @@ public class MediaCodecHelper { return null; } - public static MediaCodecInfo findProbableSafeDecoder() { + public static MediaCodecInfo findProbableSafeDecoder(String mimeType, int requiredProfile) { // First look for a preferred decoder by name MediaCodecInfo info = findPreferredDecoder(); if (info != null) { @@ -234,12 +245,12 @@ public class MediaCodecHelper { // Now look for decoders we know are safe try { // If this function completes, it will determine if the decoder is safe - return findKnownSafeDecoder(); + return findKnownSafeDecoder(mimeType, requiredProfile); } catch (Exception e) { // Some buggy devices seem to throw exceptions // from getCapabilitiesForType() so we'll just assume // they're okay and go with the first one we find - return findFirstDecoder(); + return findFirstDecoder(mimeType); } } @@ -247,7 +258,7 @@ public class MediaCodecHelper { // since some bad decoders can throw IllegalArgumentExceptions unexpectedly // and we want to be sure all callers are handling this possibility @SuppressWarnings("RedundantThrows") - private static MediaCodecInfo findKnownSafeDecoder() throws Exception { + private static MediaCodecInfo findKnownSafeDecoder(String mimeType, int requiredProfile) throws Exception { for (MediaCodecInfo codecInfo : getMediaCodecList()) { // Skip encoders if (codecInfo.isEncoder()) { @@ -260,21 +271,26 @@ public class MediaCodecHelper { continue; } - // Find a decoder that supports H.264 high profile + // Find a decoder that supports the requested video format for (String mime : codecInfo.getSupportedTypes()) { - if (mime.equalsIgnoreCase("video/avc")) { + if (mime.equalsIgnoreCase(mimeType)) { LimeLog.info("Examining decoder capabilities of "+codecInfo.getName()); - + CodecCapabilities caps = codecInfo.getCapabilitiesForType(mime); - for (CodecProfileLevel profile : caps.profileLevels) { - if (profile.profile == CodecProfileLevel.AVCProfileHigh) { - LimeLog.info("Decoder "+codecInfo.getName()+" supports high profile"); - LimeLog.info("Selected decoder: "+codecInfo.getName()); - return codecInfo; + + if (requiredProfile != -1) { + for (CodecProfileLevel profile : caps.profileLevels) { + if (profile.profile == requiredProfile) { + LimeLog.info("Decoder " + codecInfo.getName() + " supports required profile"); + return codecInfo; + } } + + LimeLog.info("Decoder " + codecInfo.getName() + " does NOT support required profile"); + } + else { + return codecInfo; } - - LimeLog.info("Decoder "+codecInfo.getName()+" does NOT support high profile"); } } } diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java index f1d9091e..9972d69c 100644 --- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java +++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java @@ -21,6 +21,7 @@ public class PreferenceConfiguration { private static final String MULTI_CONTROLLER_PREF_STRING = "checkbox_multi_controller"; private static final String ENABLE_51_SURROUND_PREF_STRING = "checkbox_51_surround"; private static final String USB_DRIVER_PREF_SRING = "checkbox_usb_driver"; + private static final String VIDEO_FORMAT_PREF_STRING = "video_format"; private static final int BITRATE_DEFAULT_720_30 = 5; private static final int BITRATE_DEFAULT_720_60 = 10; @@ -42,14 +43,19 @@ public class PreferenceConfiguration { private static final boolean DEFAULT_MULTI_CONTROLLER = true; private static final boolean DEFAULT_ENABLE_51_SURROUND = false; private static final boolean DEFAULT_USB_DRIVER = true; + private static final String DEFAULT_VIDEO_FORMAT = "auto"; public static final int FORCE_HARDWARE_DECODER = -1; public static final int AUTOSELECT_DECODER = 0; public static final int FORCE_SOFTWARE_DECODER = 1; + public static final int FORCE_H265_ON = -1; + public static final int AUTOSELECT_H265 = 0; + public static final int FORCE_H265_OFF = 1; + public int width, height, fps; public int bitrate; - public int decoder; + public int decoder, videoFormat; public int deadzonePercentage; public boolean stretchVideo, enableSops, playHostAudio, disableWarnings; public String language; @@ -124,6 +130,25 @@ public class PreferenceConfiguration { } } + private static int getVideoFormatValue(Context context) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + + String str = prefs.getString(VIDEO_FORMAT_PREF_STRING, DEFAULT_VIDEO_FORMAT); + if (str.equals("auto")) { + return AUTOSELECT_H265; + } + else if (str.equals("forceh265")) { + return FORCE_H265_ON; + } + else if (str.equals("neverh265")) { + return FORCE_H265_OFF; + } + else { + // Should never get here + return AUTOSELECT_H265; + } + } + public static PreferenceConfiguration readPreferences(Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); PreferenceConfiguration config = new PreferenceConfiguration(); @@ -168,6 +193,7 @@ public class PreferenceConfiguration { } config.decoder = getDecoderValue(context); + config.videoFormat = getVideoFormatValue(context); config.deadzonePercentage = prefs.getInt(DEADZONE_PREF_STRING, DEFAULT_DEADZONE); diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index ec7c150c..d4191bdb 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -38,4 +38,15 @@ software hardware + + + Use H.265 only if safe + Always use H.265 if available + Never use H.265 + + + auto + forceh265 + neverh265 + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d633c26a..3e28bd23 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -123,4 +123,7 @@ Advanced Settings Change decoder Software decoding may improve video latency at lower streaming settings + Change H.265 settings + H.265 lowers video bandwidth requirements but requires a very recent device. + diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 7b9a3b3d..c78cdd8b 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -89,6 +89,13 @@ android:entryValues="@array/decoder_values" android:summary="@string/summary_decoder_list" android:defaultValue="auto" /> +