From b7c588a988272ce840f488f2f907ba3737247f82 Mon Sep 17 00:00:00 2001 From: gz0119 Date: Mon, 3 Mar 2025 15:16:44 +0800 Subject: [PATCH 1/4] Expand the metadata to 16 bytes, 13-16 is the screen direction --- .DS_Store | Bin 0 -> 6148 bytes app/.DS_Store | Bin 0 -> 6148 bytes app/src/demuxer.c | 15 +++++++++------ .../main/java/com/genymobile/scrcpy/Server.java | 4 ++-- .../com/genymobile/scrcpy/device/Device.java | 2 +- .../com/genymobile/scrcpy/device/Streamer.java | 16 ++++++++++++---- 6 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 .DS_Store create mode 100644 app/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2b0d21d73170425fc9a394a026c80e2cb5eb5bad GIT binary patch literal 6148 zcmZQzU|@7AO)+F(5MW?n;9!8zOq>i@0Z1N%F(jFwA}k>DKxPydB<18MF)%RfOe%oN zjZ%X<1VC}e%#g@Xz)+A>jvRkEnZ+dr2G;i=7gS zqCvcn{QR6G7&|d3EHkw{UO>b-Kd&S)GcUCWq$D^qB{eCrC?-5JFD1X+DZex?r5LOi zD#5|Y!5J?gSzT>pY^I}NXkbyRqfl*VWMHDBU~Xn!Tg%BIs;qAv6rY`wo0s1W2~9>u z2+hC?rD0SL0|NupJ7vK|c{%xc>5#<9z{XI_kjhZRPzEB0i&s%Rh2~*ckc`r!Aut*O zqalD90?kXDcykX8^4(#pUHVu9tsS{WFjS{cFJ5C#TDaF+x`gS9g-GJv%+FfxF(Gr(GY zj1cV%j8K~yp*<8vP>%*=K14eMBSbscZKK3!2#kgRA_SNrOaV~+@5;b{tN#yCHA;?# zz-R~z%Mf5>aS3*D0#%wgya%dlLG@_@R323OgQ{ajP(6(h16RdNkO4&rs4%Fy2WbV- Y;HsFB0aBBXHUwZHG)j+#0R2M%0D@tMt^fc4 literal 0 HcmV?d00001 diff --git a/app/.DS_Store b/app/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b65ed92e7f2ce66779fb6000d44e8432cd0205a2 GIT binary patch literal 6148 zcmZQzU|@7AO)+F(5MW?n;9!8zj35RBCIAV8Fop~hR0Kpbg3Kr`NXp4iVqjp{nN$Fk z8|)Ow?aU0t3`GpdN#)4y&&ez!A4ToZP(pZb*1CGD2tu zUMLNtdKefOpx!A9F3QWv&r1hIHcWby9u0xf5Eu=C(GVC70R{$WCBnfy8W^J?Fd71* zA%GSFpz=Wh+I)0?(hU$ABn2uzK+R_m%>vU3?gv2BfV6_-Kw3dGNGk&)hy|7hYh_?$ zfM{g|cSAsB5~xc8qQTl37#YCY85kMB+8JOiUq*;_21bZ>23Y5X5u%-e5u%-e5uzRD zyis~I1V%#u8UoA^S^!l4yE4GD5JYs891Vfd5Ev05z{uhf?BWEjl(G94RM&#)(*&qA zsP>0c$DoRu0VEBo*1=UV6J$V90;&`w4$=yu!BsIM1EeM&Z3w_ZXp|le0s4mk0IwlQ Axc~qF literal 0 HcmV?d00001 diff --git a/app/src/demuxer.c b/app/src/demuxer.c index 885cd6ee..0eb1a171 100644 --- a/app/src/demuxer.c +++ b/app/src/demuxer.c @@ -9,7 +9,7 @@ #include "util/binary.h" #include "util/log.h" -#define SC_PACKET_HEADER_SIZE 12 +#define SC_PACKET_HEADER_SIZE 16 #define SC_PACKET_FLAG_CONFIG (UINT64_C(1) << 63) #define SC_PACKET_FLAG_KEY_FRAME (UINT64_C(1) << 62) @@ -82,11 +82,11 @@ sc_demuxer_recv_packet(struct sc_demuxer *demuxer, AVPacket *packet) { // The video and audio streams contain a sequence of raw packets (as // provided by MediaCodec), each prefixed with a "meta" header. // - // The "meta" header length is 12 bytes: - // [. . . . . . . .|. . . .]. . . . . . . . . . . . . . . ... - // <-------------> <-----> <-----------------------------... - // PTS packet raw packet - // size + // The "meta" header length is 16 bytes: + // [. . . . . . . .|. . . .][. . . .]. . . . . . . . . . . . . . . ... + // <-------------> <------> <------> <-----------------------------... + // PTS packet screen raw packet + // size orientation // // It is followed by bytes containing the packet/frame. // @@ -107,6 +107,8 @@ sc_demuxer_recv_packet(struct sc_demuxer *demuxer, AVPacket *packet) { uint64_t pts_flags = sc_read64be(header); uint32_t len = sc_read32be(&header[8]); + uint32_t screen_orientation = sc_read32be(&header[12]); + LOGD("Screen Orientation: %u", screen_orientation); assert(len); if (av_new_packet(packet, len)) { @@ -131,6 +133,7 @@ sc_demuxer_recv_packet(struct sc_demuxer *demuxer, AVPacket *packet) { } packet->dts = packet->pts; + return true; } diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index 09cfd6cf..b40632f0 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -132,7 +132,7 @@ public final class Server { audioCapture = new AudioPlaybackCapture(options.getAudioDup()); } - Streamer audioStreamer = new Streamer(connection.getAudioFd(), audioCodec, options.getSendCodecMeta(), options.getSendFrameMeta()); + Streamer audioStreamer = new Streamer(connection.getAudioFd(), audioCodec, options.getSendCodecMeta(), options.getSendFrameMeta(), options.getDisplayId()); AsyncProcessor audioRecorder; if (audioCodec == AudioCodec.RAW) { audioRecorder = new AudioRawRecorder(audioCapture, audioStreamer); @@ -144,7 +144,7 @@ public final class Server { if (video) { Streamer videoStreamer = new Streamer(connection.getVideoFd(), options.getVideoCodec(), options.getSendCodecMeta(), - options.getSendFrameMeta()); + options.getSendFrameMeta(), options.getDisplayId()); SurfaceCapture surfaceCapture; if (options.getVideoSource() == VideoSource.DISPLAY) { NewDisplay newDisplay = options.getNewDisplay(); diff --git a/server/src/main/java/com/genymobile/scrcpy/device/Device.java b/server/src/main/java/com/genymobile/scrcpy/device/Device.java index 3553dc27..687ec4a4 100644 --- a/server/src/main/java/com/genymobile/scrcpy/device/Device.java +++ b/server/src/main/java/com/genymobile/scrcpy/device/Device.java @@ -210,7 +210,7 @@ public final class Device { } } - private static int getCurrentRotation(int displayId) { + public static int getCurrentRotation(int displayId) { assert displayId != DISPLAY_ID_NONE; if (displayId == 0) { diff --git a/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java b/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java index f54d0567..99cc343c 100644 --- a/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java +++ b/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; +import com.genymobile.scrcpy.util.Ln; public final class Streamer { @@ -21,14 +22,16 @@ public final class Streamer { private final Codec codec; private final boolean sendCodecMeta; private final boolean sendFrameMeta; + private final int displayId; - private final ByteBuffer headerBuffer = ByteBuffer.allocate(12); + private final ByteBuffer headerBuffer = ByteBuffer.allocate(16); - public Streamer(FileDescriptor fd, Codec codec, boolean sendCodecMeta, boolean sendFrameMeta) { + public Streamer(FileDescriptor fd, Codec codec, boolean sendCodecMeta, boolean sendFrameMeta, int displayId) { this.fd = fd; this.codec = codec; this.sendCodecMeta = sendCodecMeta; this.sendFrameMeta = sendFrameMeta; + this.displayId = displayId; } public Codec getCodec() { @@ -76,11 +79,15 @@ public final class Streamer { } if (sendFrameMeta) { - writeFrameMeta(fd, buffer.remaining(), pts, config, keyFrame); + int screenOrientation = getScreenOrientation(); + writeFrameMeta(fd, buffer.remaining(), pts, config, keyFrame, screenOrientation); } IO.writeFully(fd, buffer); } + private int getScreenOrientation() { + return Device.getCurrentRotation(this.displayId); + } public void writePacket(ByteBuffer codecBuffer, MediaCodec.BufferInfo bufferInfo) throws IOException { long pts = bufferInfo.presentationTimeUs; @@ -89,7 +96,7 @@ public final class Streamer { writePacket(codecBuffer, pts, config, keyFrame); } - private void writeFrameMeta(FileDescriptor fd, int packetSize, long pts, boolean config, boolean keyFrame) throws IOException { + private void writeFrameMeta(FileDescriptor fd, int packetSize, long pts, boolean config, boolean keyFrame, int screenOrientation) throws IOException { headerBuffer.clear(); long ptsAndFlags; @@ -104,6 +111,7 @@ public final class Streamer { headerBuffer.putLong(ptsAndFlags); headerBuffer.putInt(packetSize); + headerBuffer.putInt(screenOrientation); headerBuffer.flip(); IO.writeFully(fd, headerBuffer); } From fa8d262704e73597e07373f657403da6f5ad4662 Mon Sep 17 00:00:00 2001 From: gz0119 Date: Mon, 3 Mar 2025 15:19:29 +0800 Subject: [PATCH 2/4] Ignore hidden files on mac --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 1 + app/.DS_Store | Bin 6148 -> 0 bytes 3 files changed, 1 insertion(+) delete mode 100644 .DS_Store delete mode 100644 app/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 2b0d21d73170425fc9a394a026c80e2cb5eb5bad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmZQzU|@7AO)+F(5MW?n;9!8zOq>i@0Z1N%F(jFwA}k>DKxPydB<18MF)%RfOe%oN zjZ%X<1VC}e%#g@Xz)+A>jvRkEnZ+dr2G;i=7gS zqCvcn{QR6G7&|d3EHkw{UO>b-Kd&S)GcUCWq$D^qB{eCrC?-5JFD1X+DZex?r5LOi zD#5|Y!5J?gSzT>pY^I}NXkbyRqfl*VWMHDBU~Xn!Tg%BIs;qAv6rY`wo0s1W2~9>u z2+hC?rD0SL0|NupJ7vK|c{%xc>5#<9z{XI_kjhZRPzEB0i&s%Rh2~*ckc`r!Aut*O zqalD90?kXDcykX8^4(#pUHVu9tsS{WFjS{cFJ5C#TDaF+x`gS9g-GJv%+FfxF(Gr(GY zj1cV%j8K~yp*<8vP>%*=K14eMBSbscZKK3!2#kgRA_SNrOaV~+@5;b{tN#yCHA;?# zz-R~z%Mf5>aS3*D0#%wgya%dlLG@_@R323OgQ{ajP(6(h16RdNkO4&rs4%Fy2WbV- Y;HsFB0aBBXHUwZHG)j+#0R2M%0D@tMt^fc4 diff --git a/.gitignore b/.gitignore index 26d977ac..dc7d5682 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ build/ /x/ local.properties /scrcpy-server +.DS_Store \ No newline at end of file diff --git a/app/.DS_Store b/app/.DS_Store deleted file mode 100644 index b65ed92e7f2ce66779fb6000d44e8432cd0205a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmZQzU|@7AO)+F(5MW?n;9!8zj35RBCIAV8Fop~hR0Kpbg3Kr`NXp4iVqjp{nN$Fk z8|)Ow?aU0t3`GpdN#)4y&&ez!A4ToZP(pZb*1CGD2tu zUMLNtdKefOpx!A9F3QWv&r1hIHcWby9u0xf5Eu=C(GVC70R{$WCBnfy8W^J?Fd71* zA%GSFpz=Wh+I)0?(hU$ABn2uzK+R_m%>vU3?gv2BfV6_-Kw3dGNGk&)hy|7hYh_?$ zfM{g|cSAsB5~xc8qQTl37#YCY85kMB+8JOiUq*;_21bZ>23Y5X5u%-e5u%-e5uzRD zyis~I1V%#u8UoA^S^!l4yE4GD5JYs891Vfd5Ev05z{uhf?BWEjl(G94RM&#)(*&qA zsP>0c$DoRu0VEBo*1=UV6J$V90;&`w4$=yu!BsIM1EeM&Z3w_ZXp|le0s4mk0IwlQ Axc~qF From 7c167fd67e899fcd7485dc7353e4eb8aadd4e112 Mon Sep 17 00:00:00 2001 From: gz0119 Date: Mon, 3 Mar 2025 16:13:09 +0800 Subject: [PATCH 3/4] Optimize the output method of direction information --- app/src/demuxer.c | 7 ++++++- .../main/java/com/genymobile/scrcpy/device/Streamer.java | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/demuxer.c b/app/src/demuxer.c index 0eb1a171..690e1620 100644 --- a/app/src/demuxer.c +++ b/app/src/demuxer.c @@ -77,6 +77,8 @@ sc_demuxer_recv_video_size(struct sc_demuxer *demuxer, uint32_t *width, return true; } +uint32_t last_screen_orientation = -1; + static bool sc_demuxer_recv_packet(struct sc_demuxer *demuxer, AVPacket *packet) { // The video and audio streams contain a sequence of raw packets (as @@ -108,7 +110,10 @@ sc_demuxer_recv_packet(struct sc_demuxer *demuxer, AVPacket *packet) { uint64_t pts_flags = sc_read64be(header); uint32_t len = sc_read32be(&header[8]); uint32_t screen_orientation = sc_read32be(&header[12]); - LOGD("Screen Orientation: %u", screen_orientation); + if(last_screen_orientation != screen_orientation){ + last_screen_orientation = screen_orientation; + LOGD("Screen Orientation: %u", last_screen_orientation); + }; assert(len); if (av_new_packet(packet, len)) { diff --git a/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java b/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java index 99cc343c..a3627d08 100644 --- a/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java +++ b/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java @@ -11,7 +11,6 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; -import com.genymobile.scrcpy.util.Ln; public final class Streamer { From 8cfdfd0785444e5b65b0cae9ee0983c41db654cd Mon Sep 17 00:00:00 2001 From: gz0119 Date: Mon, 10 Mar 2025 20:52:59 +0800 Subject: [PATCH 4/4] Handling header conflicts --- app/src/demuxer.c | 18 ++++++ .../com/genymobile/scrcpy/device/Device.java | 9 +++ .../genymobile/scrcpy/device/Streamer.java | 7 ++- .../scrcpy/video/SurfaceEncoder.java | 59 ++++++++++++++++++- .../scrcpy/wrappers/WindowManager.java | 23 ++++++++ 5 files changed, 110 insertions(+), 6 deletions(-) diff --git a/app/src/demuxer.c b/app/src/demuxer.c index 690e1620..b98e3e4b 100644 --- a/app/src/demuxer.c +++ b/app/src/demuxer.c @@ -13,6 +13,7 @@ #define SC_PACKET_FLAG_CONFIG (UINT64_C(1) << 63) #define SC_PACKET_FLAG_KEY_FRAME (UINT64_C(1) << 62) +#define PACKET_FLAG_VIDEO_SESSION (UINT64_C(1) << 61) #define SC_PACKET_PTS_MASK (SC_PACKET_FLAG_KEY_FRAME - 1) @@ -76,6 +77,18 @@ sc_demuxer_recv_video_size(struct sc_demuxer *demuxer, uint32_t *width, *height = sc_read32be(data + 4); return true; } +static void +handle_video_session_packet(AVPacket *packet) { + if (!packet || !packet->data || packet->size < 12) { + LOGE("Invalid packet data"); + return; + } + const uint8_t *data = packet->data; + int width = sc_read32be(data); + int height = sc_read32be(data + 4); + int orientation = sc_read32be(data + 8); + LOGD("Orientation=%d, Width=%d, Height=%d, Size=%d", orientation, width, height, packet->size); +} uint32_t last_screen_orientation = -1; @@ -127,6 +140,11 @@ sc_demuxer_recv_packet(struct sc_demuxer *demuxer, AVPacket *packet) { return false; } + if (pts_flags & PACKET_FLAG_VIDEO_SESSION) { + handle_video_session_packet(packet); + return true; + } + if (pts_flags & SC_PACKET_FLAG_CONFIG) { packet->pts = AV_NOPTS_VALUE; } else { diff --git a/server/src/main/java/com/genymobile/scrcpy/device/Device.java b/server/src/main/java/com/genymobile/scrcpy/device/Device.java index 687ec4a4..732c7ba8 100644 --- a/server/src/main/java/com/genymobile/scrcpy/device/Device.java +++ b/server/src/main/java/com/genymobile/scrcpy/device/Device.java @@ -24,6 +24,7 @@ import android.view.InputDevice; import android.view.InputEvent; import android.view.KeyCharacterMap; import android.view.KeyEvent; +import android.graphics.Point; import java.util.ArrayList; import java.util.List; @@ -220,6 +221,14 @@ public final class Device { DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(displayId); return displayInfo.getRotation(); } + public static Size getSize(int displayId){ + assert displayId != DISPLAY_ID_NONE; + if (displayId == 0) { + return ServiceManager.getWindowManager().getSize(displayId); + } + DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(displayId); + return displayInfo.getSize(); + } public static List listApps() { List apps = new ArrayList<>(); diff --git a/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java b/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java index a3627d08..589a23fc 100644 --- a/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java +++ b/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java @@ -13,9 +13,9 @@ import java.nio.ByteOrder; import java.util.Arrays; public final class Streamer { - private static final long PACKET_FLAG_CONFIG = 1L << 63; private static final long PACKET_FLAG_KEY_FRAME = 1L << 62; + public static final long PACKET_FLAG_VIDEO_SESSION = 1L << 61; private final FileDescriptor fd; private final Codec codec; @@ -23,7 +23,8 @@ public final class Streamer { private final boolean sendFrameMeta; private final int displayId; - private final ByteBuffer headerBuffer = ByteBuffer.allocate(16); + private final int HEADER_PACKET_SIZE = 12; + private final ByteBuffer headerBuffer = ByteBuffer.allocate(HEADER_PACKET_SIZE); public Streamer(FileDescriptor fd, Codec codec, boolean sendCodecMeta, boolean sendFrameMeta, int displayId) { this.fd = fd; @@ -48,7 +49,7 @@ public final class Streamer { public void writeVideoHeader(Size videoSize) throws IOException { if (sendCodecMeta) { - ByteBuffer buffer = ByteBuffer.allocate(12); + ByteBuffer buffer = ByteBuffer.allocate(HEADER_PACKET_SIZE); buffer.putInt(codec.getId()); buffer.putInt(videoSize.getWidth()); buffer.putInt(videoSize.getHeight()); diff --git a/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java b/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java index 236a5f48..7b722927 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java @@ -3,9 +3,11 @@ package com.genymobile.scrcpy.video; import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.AsyncProcessor; import com.genymobile.scrcpy.Options; +import com.genymobile.scrcpy.device.Device; import com.genymobile.scrcpy.device.ConfigurationException; import com.genymobile.scrcpy.device.Size; import com.genymobile.scrcpy.device.Streamer; +import com.genymobile.scrcpy.device.Orientation; import com.genymobile.scrcpy.util.Codec; import com.genymobile.scrcpy.util.CodecOption; import com.genymobile.scrcpy.util.CodecUtils; @@ -25,6 +27,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Stream; public class SurfaceEncoder implements AsyncProcessor { @@ -44,6 +47,16 @@ public class SurfaceEncoder implements AsyncProcessor { private final float maxFps; private final boolean downsizeOnError; + private int orientation = -100; + private final int displayId; + private boolean sendCodeMeta; + private boolean sendFrameMeta; + private int maxSize; + private Size originalSize; + private Size displaySize; + private Orientation captureOrientation; + private Orientation.Lock captureOrientationLock; + private boolean firstFrameSent; private int consecutiveErrors; @@ -60,13 +73,22 @@ public class SurfaceEncoder implements AsyncProcessor { this.codecOptions = options.getVideoCodecOptions(); this.encoderName = options.getVideoEncoder(); this.downsizeOnError = options.getDownsizeOnError(); + + this.displayId = options.getDisplayId(); + this.sendCodeMeta = options.getSendCodecMeta(); + this.sendFrameMeta = options.getSendFrameMeta(); + this.originalSize = Device.getSize(this.displayId); + int maxSize = options.getMaxSize(); + int max = maxSize == 0 ? chooseMaxSizeFallback(this.originalSize) : maxSize; + this.displaySize = this.originalSize.limit(max).round8(); + this.captureOrientation = options.getCaptureOrientation(); + this.captureOrientationLock = options.getCaptureOrientationLock(); } private void streamCapture() throws IOException, ConfigurationException { Codec codec = streamer.getCodec(); MediaCodec mediaCodec = createMediaCodec(codec, encoderName); MediaFormat format = createFormat(codec.getMimeType(), videoBitRate, maxFps, codecOptions); - capture.init(reset); try { @@ -182,7 +204,7 @@ public class SurfaceEncoder implements AsyncProcessor { return true; } - private static int chooseMaxSizeFallback(Size failedSize) { + public static int chooseMaxSizeFallback(Size failedSize) { int currentMaxSize = Math.max(failedSize.getWidth(), failedSize.getHeight()); for (int value : MAX_SIZE_FALLBACK) { if (value < currentMaxSize) { @@ -194,6 +216,28 @@ public class SurfaceEncoder implements AsyncProcessor { return 0; } + private Size getSize(int orientation){ + switch (orientation) { + case 0: + case 4: + return this.displaySize; + case 1: + case 3: + return new Size(this.displaySize.getHeight(),this.displaySize.getWidth()); + } + return new Size(0,0); + } + private ByteBuffer getCurrentVideoSession(int orientation){ + ByteBuffer buffer = ByteBuffer.allocate(20); + Size size = getSize(orientation); + int width = size.getWidth(); + int height = size.getHeight(); + buffer.putInt(width); + buffer.putInt(height); + buffer.putInt(orientation); + buffer.flip(); + return buffer; + } private void encode(MediaCodec codec, Streamer streamer) throws IOException { MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); @@ -201,6 +245,16 @@ public class SurfaceEncoder implements AsyncProcessor { do { int outputBufferId = codec.dequeueOutputBuffer(bufferInfo, -1); try { + // If the frame width and height do not change, it will not be re-encoded + // Therefore, it is necessary to monitor each frame. + // For example: horizontal (1->3), vertical (0->4) + int orientation = Device.getCurrentRotation(displayId); + if(this.orientation != orientation){ + this.orientation = orientation; + ByteBuffer videoSession = getCurrentVideoSession(orientation); + streamer.writePacket(videoSession,Streamer.PACKET_FLAG_VIDEO_SESSION,false,false); + } + eos = (bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0; // On EOS, there might be data or not, depending on bufferInfo.size if (outputBufferId >= 0 && bufferInfo.size > 0) { @@ -212,7 +266,6 @@ public class SurfaceEncoder implements AsyncProcessor { firstFrameSent = true; consecutiveErrors = 0; } - streamer.writePacket(codecBuffer, bufferInfo); } } finally { diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/WindowManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/WindowManager.java index 7ba5cc06..498ba6cf 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/WindowManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/WindowManager.java @@ -2,12 +2,15 @@ package com.genymobile.scrcpy.wrappers; import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.util.Ln; +import com.genymobile.scrcpy.device.Size; import android.annotation.TargetApi; +import android.graphics.Point; import android.os.Build; import android.os.IInterface; import android.view.IDisplayWindowListener; +// import java.awt.Point; import java.lang.reflect.Method; public final class WindowManager { @@ -42,6 +45,26 @@ public final class WindowManager { this.manager = manager; } + private Method getGetSizeMethod; + private Method getGetSizeMethod() throws NoSuchMethodException { + if (getGetSizeMethod == null) { + Class cls = manager.getClass(); + getGetSizeMethod = cls.getMethod("getInitialDisplaySize",int.class, Point.class); + } + return getGetSizeMethod; + } + public Size getSize(int displayId) { + try { + Method method = getGetSizeMethod(); + Point size = new Point(); + method.invoke(manager, displayId, size); + return new Size(size.x, size.y); + } catch (ReflectiveOperationException e) { + Ln.e("Could not invoke method", e); + return new Size(0,0); + } + } + private Method getGetRotationMethod() throws NoSuchMethodException { if (getRotationMethod == null) { Class cls = manager.getClass();