diff options
| author | Lena <lena@omega> | 2026-07-01 00:00:00 +0000 |
|---|---|---|
| committer | Lena <lena@omega> | 2026-07-01 00:00:00 +0000 |
| commit | 735ca8b58dc341f4521a162346ba14fe943eb2bb (patch) | |
| tree | 423fcddb7ee7e918e59496821aeae096e6bce377 /app/src/main/java/invalid/lena/scrcpy | |
| parent | eb0c8951196c637e44daf3c0617b131b997d5d2c (diff) | |
| download | scrcpy-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/src/main/java/invalid/lena/scrcpy')
| -rw-r--r-- | app/src/main/java/invalid/lena/scrcpy/VideoSink.java | 14 |
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; |