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 <https://github.com/Genymobile/scrcpy/issues/3693>
This commit is contained in:
parent
a52053421a
commit
07806ba915
1 changed files with 19 additions and 1 deletions
|
@ -9,6 +9,7 @@ import android.media.MediaCodecList;
|
||||||
import android.media.MediaFormat;
|
import android.media.MediaFormat;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
|
@ -27,6 +28,7 @@ public class ScreenEncoder implements Device.RotationListener {
|
||||||
|
|
||||||
// Keep the values in descending order
|
// Keep the values in descending order
|
||||||
private static final int[] MAX_SIZE_FALLBACK = {2560, 1920, 1600, 1280, 1024, 800};
|
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_CONFIG = 1L << 63;
|
||||||
private static final long PACKET_FLAG_KEY_FRAME = 1L << 62;
|
private static final long PACKET_FLAG_KEY_FRAME = 1L << 62;
|
||||||
|
@ -43,6 +45,7 @@ public class ScreenEncoder implements Device.RotationListener {
|
||||||
private long ptsOrigin;
|
private long ptsOrigin;
|
||||||
|
|
||||||
private boolean firstFrameSent;
|
private boolean firstFrameSent;
|
||||||
|
private int consecutiveErrors;
|
||||||
|
|
||||||
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, List<CodecOption> codecOptions, String encoderName,
|
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, List<CodecOption> codecOptions, String encoderName,
|
||||||
boolean downsizeOnError) {
|
boolean downsizeOnError) {
|
||||||
|
@ -128,11 +131,25 @@ public class ScreenEncoder implements Device.RotationListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean prepareRetry(Device device, ScreenInfo screenInfo) {
|
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
|
// Must fail immediately
|
||||||
return false;
|
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());
|
int newMaxSize = chooseMaxSizeFallback(screenInfo.getVideoSize());
|
||||||
Ln.i("newMaxSize = " + newMaxSize);
|
Ln.i("newMaxSize = " + newMaxSize);
|
||||||
if (newMaxSize == 0) {
|
if (newMaxSize == 0) {
|
||||||
|
@ -181,6 +198,7 @@ public class ScreenEncoder implements Device.RotationListener {
|
||||||
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
|
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
|
||||||
// If this is not a config packet, then it contains a frame
|
// If this is not a config packet, then it contains a frame
|
||||||
firstFrameSent = true;
|
firstFrameSent = true;
|
||||||
|
consecutiveErrors = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|
Loading…
Reference in a new issue