aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorLena <lena@omega>2026-07-01 00:00:00 +0000
committerLena <lena@omega>2026-07-01 00:00:00 +0000
commit735ca8b58dc341f4521a162346ba14fe943eb2bb (patch)
tree423fcddb7ee7e918e59496821aeae096e6bce377 /app
parenteb0c8951196c637e44daf3c0617b131b997d5d2c (diff)
downloadscrcpy-android-735ca8b58dc341f4521a162346ba14fe943eb2bb.tar.gz
app: guard VideoSink.submit against torn-down codec
reconfigure() tears the codec down outside the lock, so an in-flight MediaCodec callback can reach submit() while `codec` is null. The NPE lands on the callback handler thread, which has no catch and kills the process. Drop the frame instead, like any back-pressure casualty. Also rewrite the back-pressure comment: it described a keyframe-aware drop policy this class cannot implement (the keyframe flag never reaches it). The real policy protects config frames only.
Diffstat (limited to 'app')
-rw-r--r--app/src/main/java/invalid/lena/scrcpy/VideoSink.java14
1 files changed, 9 insertions, 5 deletions
diff --git a/app/src/main/java/invalid/lena/scrcpy/VideoSink.java b/app/src/main/java/invalid/lena/scrcpy/VideoSink.java
index fa8248b..2d69339 100644
--- a/app/src/main/java/invalid/lena/scrcpy/VideoSink.java
+++ b/app/src/main/java/invalid/lena/scrcpy/VideoSink.java
@@ -19,10 +19,11 @@ import java.util.Iterator;
// meet through a small queue of pending frames waiting for input buffers,
// plus a corresponding pool of free input buffer indices.
//
-// Back-pressure policy: when both queues fill, drop the *next* incoming
-// frame unless it is a config or keyframe (we have no way to know its
-// type from outside). For v1 we simply drop oldest pending non-keyframes
-// if the pending queue grows past a small bound.
+// Back-pressure policy: when no input buffer is free and the pending
+// queue is full, the oldest pending non-config frame is dropped. Config
+// frames (CSD) always survive - the decoder cannot start without them.
+// Keyframes are not distinguishable here (the flag stays in VideoStream)
+// so they drop like any delta frame; the picture heals at the next one.
//
// Output timing: releaseOutputBuffer is called with an absolute nano
// timestamp on the System.nanoTime clock, derived from the wire PTS so
@@ -203,8 +204,11 @@ public final class VideoSink implements VideoFrames {
}
}
- // Must be called with `lock` held.
+ // Must be called with `lock` held. codec can be null mid-reconfigure
+ // (teardownCodec runs unlocked); the frame is dropped like any other
+ // back-pressure casualty.
private void submit(Frame f, int idx) {
+ if (codec == null) return;
try {
ByteBuffer buf = codec.getInputBuffer(idx);
if (buf == null) return;