aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/invalid/lena/scrcpy/VideoStream.java
diff options
context:
space:
mode:
authorLena <lena@omega>2026-08-01 00:00:00 +0000
committerLena <lena@omega>2026-08-01 00:00:00 +0000
commit852a8a00273c9128efeed0217a8e5d3fcd8bf780 (patch)
treec72f959731fa3c7c809cf1a0222363b6c9c9b03b /app/src/main/java/invalid/lena/scrcpy/VideoStream.java
parentf379b93d52bf0dbd3816ec3f64d165314771d2a6 (diff)
downloadscrcpy-android-852a8a00273c9128efeed0217a8e5d3fcd8bf780.tar.gz
app: harden mirroring lifecycle and state
Diffstat (limited to 'app/src/main/java/invalid/lena/scrcpy/VideoStream.java')
-rw-r--r--app/src/main/java/invalid/lena/scrcpy/VideoStream.java26
1 files changed, 14 insertions, 12 deletions
diff --git a/app/src/main/java/invalid/lena/scrcpy/VideoStream.java b/app/src/main/java/invalid/lena/scrcpy/VideoStream.java
index 7ecb3f1..9d870e5 100644
--- a/app/src/main/java/invalid/lena/scrcpy/VideoStream.java
+++ b/app/src/main/java/invalid/lena/scrcpy/VideoStream.java
@@ -34,11 +34,11 @@ public final class VideoStream {
private static final int FLAG_SESSION_INT_BIT = 0x80000000;
private static final int MAX_FRAME_SIZE = 8 * 1024 * 1024;
+ private static final int MAX_DIMENSION = 16 * 1024;
private final InputStream source;
private final VideoFrames sink;
private final SizeListener sizeListener;
- private volatile VideoRecorder recorder; // optional tap
private volatile Runnable onEnd; // fired once when run() exits
private Thread thread;
private volatile boolean stop;
@@ -69,10 +69,6 @@ public final class VideoStream {
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}
- public void setRecorder(VideoRecorder r) {
- this.recorder = r;
- }
-
// Fired exactly once, on the reader thread, when run() exits - whether
// by EOF, error, or stop(). The video socket is the authoritative
// stream: when it ends mid-session the link is gone, so Session uses
@@ -89,6 +85,10 @@ public final class VideoStream {
fourcc = Wire.readBe32(four, 0);
if (fourcc == 0) throw new IOException("video: server reports stream disabled");
if (fourcc == 1) throw new IOException("video: server reports configuration error");
+ if (fourcc != Wire.CODEC_H264 && fourcc != Wire.CODEC_H265
+ && fourcc != Wire.CODEC_AV1) {
+ throw new IOException("video: unexpected codec " + Wire.fourccName(fourcc));
+ }
Log.i("video meta codec=%s", Wire.fourccName(fourcc));
byte[] tail8 = new byte[8];
@@ -117,9 +117,15 @@ public final class VideoStream {
}
private void parseSessionMeta(int hi, byte[] tail8) throws IOException {
+ if ((hi & ~0x80000001) != 0) {
+ throw new IOException("video session meta has unknown flags");
+ }
Wire.readFully(source, tail8);
int newW = Wire.readBe32(tail8, 0);
int newH = Wire.readBe32(tail8, 4);
+ if (newW < 1 || newW > MAX_DIMENSION || newH < 1 || newH > MAX_DIMENSION) {
+ throw new IOException("video size out of range: " + newW + "x" + newH);
+ }
boolean clientResize = (hi & 1) != 0;
Log.i("video session meta %dx%d client_resize=%s", newW, newH, clientResize);
@@ -133,16 +139,14 @@ public final class VideoStream {
sink.reconfigure(fourcc, curW, curH);
}
if (sizeListener != null) sizeListener.onSize(curW, curH);
- VideoRecorder r = recorder;
- if (r != null) r.onMeta(fourcc, curW, curH);
}
private void parseFrame(int hi, byte[] tail8) throws IOException {
Wire.readFully(source, tail8);
long pts = ((long) hi << 32) | (Wire.readBe32(tail8, 0) & 0xffffffffL);
int size = Wire.readBe32(tail8, 4);
- boolean cfg = (pts & FLAG_CONFIG) != 0;
- boolean key = (pts & FLAG_KEYFRAME) != 0;
+ boolean cfg = (pts & FLAG_CONFIG) != 0;
+ boolean keyframe = (pts & FLAG_KEYFRAME) != 0;
long ptsUs = pts & PTS_MASK;
if (size <= 0 || size > MAX_FRAME_SIZE) {
@@ -154,8 +158,6 @@ public final class VideoStream {
byte[] payload = new byte[size];
Wire.readFully(source, payload);
- sink.feed(payload, ptsUs, cfg);
- VideoRecorder r = recorder;
- if (r != null) r.onFrame(payload, ptsUs, cfg, key);
+ sink.feed(payload, ptsUs, cfg, keyframe);
}
}