From 07806ba9159b1f4dbd2ede77b110e254af1fd7f6 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sun, 29 Jan 2023 14:48:07 +0100 Subject: [PATCH] Retry on spurious error MediaCodec may fail spuriously, typically when stopping an encoding and starting a new one immediately (for example on device rotation). In that case, retry a few times, in many cases it should work. Refs #3693 --- .../com/genymobile/scrcpy/ScreenEncoder.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java index a695f0db..f0384e2c 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java @@ -9,6 +9,7 @@ import android.media.MediaCodecList; import android.media.MediaFormat; import android.os.Build; import android.os.IBinder; +import android.os.SystemClock; import android.view.Surface; import java.io.FileDescriptor; @@ -27,6 +28,7 @@ public class ScreenEncoder implements Device.RotationListener { // Keep the values in descending order private static final int[] MAX_SIZE_FALLBACK = {2560, 1920, 1600, 1280, 1024, 800}; + private static final int MAX_CONSECUTIVE_ERRORS = 3; private static final long PACKET_FLAG_CONFIG = 1L << 63; private static final long PACKET_FLAG_KEY_FRAME = 1L << 62; @@ -43,6 +45,7 @@ public class ScreenEncoder implements Device.RotationListener { private long ptsOrigin; private boolean firstFrameSent; + private int consecutiveErrors; public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, List codecOptions, String encoderName, boolean downsizeOnError) { @@ -128,11 +131,25 @@ public class ScreenEncoder implements Device.RotationListener { } private boolean prepareRetry(Device device, ScreenInfo screenInfo) { - if (!downsizeOnError || firstFrameSent) { + if (firstFrameSent) { + ++consecutiveErrors; + if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) { + // Definitively fail + return false; + } + + // Wait a bit to increase the probability that retrying will fix the problem + SystemClock.sleep(50); + return true; + } + + if (!downsizeOnError) { // Must fail immediately return false; } + // Downsizing on error is only enabled if an encoding failure occurs before the first frame (downsizing later could be surprising) + int newMaxSize = chooseMaxSizeFallback(screenInfo.getVideoSize()); Ln.i("newMaxSize = " + newMaxSize); if (newMaxSize == 0) { @@ -181,6 +198,7 @@ public class ScreenEncoder implements Device.RotationListener { if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) { // If this is not a config packet, then it contains a frame firstFrameSent = true; + consecutiveErrors = 0; } } } finally {