diff --git a/app/src/demuxer.c b/app/src/demuxer.c index 885cd6ee..59d44034 100644 --- a/app/src/demuxer.c +++ b/app/src/demuxer.c @@ -63,17 +63,26 @@ sc_demuxer_recv_codec_id(struct sc_demuxer *demuxer, uint32_t *codec_id) { return true; } +static void +handle_video_session_packet(uint8_t *data){ + int width = sc_read32be(data + 1); + int height = sc_read32be(data + 5); + bool isFlip = data[9] == 1; + int direction = (data[10] == (uint8_t)1 ? 2 : 0) + (data[11] == (uint8_t)1 ? 1 : 0); + LOGI("Width=%d, Height=%d, Flip=%s, Direction=%d", width, height, isFlip ? "True" : "False", direction); +} + static bool sc_demuxer_recv_video_size(struct sc_demuxer *demuxer, uint32_t *width, uint32_t *height) { - uint8_t data[8]; - ssize_t r = net_recv_all(demuxer->socket, data, 8); - if (r < 8) { + uint8_t data[12]; + ssize_t r = net_recv_all(demuxer->socket, data, 12); + if (r < 12) { return false; } - - *width = sc_read32be(data); - *height = sc_read32be(data + 4); + *width = sc_read32be(data + 1); + *height = sc_read32be(data + 5); + handle_video_session_packet(data); return true; } @@ -104,6 +113,11 @@ sc_demuxer_recv_packet(struct sc_demuxer *demuxer, AVPacket *packet) { if (r < SC_PACKET_HEADER_SIZE) { return false; } + if(header[0] == 0xff){ + handle_video_session_packet(header); + return true; + } + uint64_t pts_flags = sc_read64be(header); uint32_t len = sc_read32be(&header[8]); @@ -218,11 +232,11 @@ run_demuxer(void *data) { LOGE("Demuxer '%s': could not open codec", demuxer->name); goto finally_free_context; } - + if (!sc_packet_source_sinks_open(&demuxer->packet_source, codec_ctx)) { goto finally_free_context; } - + // Config packets must be merged with the next non-config packet only for // H.26x bool must_merge_config_packet = raw_codec_id == SC_CODEC_ID_H264 diff --git a/app/src/screen.c b/app/src/screen.c index 1d694f12..a0c6483a 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -258,8 +258,7 @@ sc_screen_frame_sink_open(struct sc_frame_sink *sink, struct sc_screen *screen = DOWNCAST(sink); - if (ctx->width <= 0 || ctx->width > 0xFFFF - || ctx->height <= 0 || ctx->height > 0xFFFF) { + if (ctx->width <= 0 || ctx->width > 0xFFFF || ctx->height <= 0 || ctx->height > 0xFFFF) { LOGE("Invalid video size: %dx%d", ctx->width, ctx->height); return false; } diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index 09cfd6cf..ab08f47d 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -152,7 +152,7 @@ public final class Server { surfaceCapture = new NewDisplayCapture(controller, options); } else { assert options.getDisplayId() != Device.DISPLAY_ID_NONE; - surfaceCapture = new ScreenCapture(controller, options); + surfaceCapture = new ScreenCapture(controller, videoStreamer, options); } } else { surfaceCapture = new CameraCapture(options); 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..5e30e157 100644 --- a/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java +++ b/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java @@ -8,6 +8,7 @@ import android.media.MediaCodec; import java.io.FileDescriptor; import java.io.IOException; +import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; @@ -16,6 +17,7 @@ public final class Streamer { 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_VIDEO_SESSION = 1L << 61; private final FileDescriptor fd; private final Codec codec; @@ -44,12 +46,24 @@ public final class Streamer { } } - public void writeVideoHeader(Size videoSize) throws IOException { + public void writeVideoHeader() throws IOException { if (sendCodecMeta) { - ByteBuffer buffer = ByteBuffer.allocate(12); + ByteBuffer buffer = ByteBuffer.allocate(4); buffer.putInt(codec.getId()); + buffer.flip(); + IO.writeFully(fd, buffer); + } + } + public void writeVideoSession(Size videoSize, boolean isFlip, int rotation) throws IOException{ + if(sendCodecMeta){ + ByteBuffer buffer = ByteBuffer.allocate(12); + buffer.put((byte) 0xff); buffer.putInt(videoSize.getWidth()); buffer.putInt(videoSize.getHeight()); + rotation = rotation * 90; + buffer.put((byte) (isFlip ? 1 : 0)); + buffer.put((byte) (rotation >= 180 ? 1 : 0)); + buffer.put((byte) (rotation >= 90 ? 1 : 0)); buffer.flip(); IO.writeFully(fd, buffer); } diff --git a/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java b/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java index 342eaeea..7df2ab9c 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java @@ -7,6 +7,7 @@ import com.genymobile.scrcpy.device.ConfigurationException; import com.genymobile.scrcpy.device.Device; import com.genymobile.scrcpy.device.DisplayInfo; import com.genymobile.scrcpy.device.Orientation; +import com.genymobile.scrcpy.device.Streamer; import com.genymobile.scrcpy.device.Size; import com.genymobile.scrcpy.opengl.AffineOpenGLFilter; import com.genymobile.scrcpy.opengl.OpenGLFilter; @@ -34,6 +35,7 @@ public class ScreenCapture extends SurfaceCapture { private Orientation.Lock captureOrientationLock; private Orientation captureOrientation; private final float angle; + private final Streamer streamer; private DisplayInfo displayInfo; private Size videoSize; @@ -46,7 +48,7 @@ public class ScreenCapture extends SurfaceCapture { private AffineMatrix transform; private OpenGLRunner glRunner; - public ScreenCapture(VirtualDisplayListener vdListener, Options options) { + public ScreenCapture(VirtualDisplayListener vdListener, Streamer streamer, Options options) { this.vdListener = vdListener; this.displayId = options.getDisplayId(); assert displayId != Device.DISPLAY_ID_NONE; @@ -57,6 +59,7 @@ public class ScreenCapture extends SurfaceCapture { assert captureOrientationLock != null; assert captureOrientation != null; this.angle = options.getAngle(); + this.streamer = streamer; } @Override @@ -77,27 +80,38 @@ public class ScreenCapture extends SurfaceCapture { } Size displaySize = displayInfo.getSize(); - displaySizeMonitor.setSessionInfo(displaySize, displayInfo.getRotation()); + int displayRotation = displayInfo.getRotation(); + displaySizeMonitor.setSessionInfo(displaySize, displayRotation); if (captureOrientationLock == Orientation.Lock.LockedInitial) { // The user requested to lock the video orientation to the current orientation captureOrientationLock = Orientation.Lock.LockedValue; - captureOrientation = Orientation.fromRotation(displayInfo.getRotation()); + captureOrientation = Orientation.fromRotation(displayRotation); } VideoFilter filter = new VideoFilter(displaySize); if (crop != null) { - boolean transposed = (displayInfo.getRotation() % 2) != 0; + boolean transposed = (displayRotation % 2) != 0; filter.addCrop(crop, transposed); } boolean locked = captureOrientationLock != Orientation.Lock.Unlocked; - filter.addOrientation(displayInfo.getRotation(), locked, captureOrientation); + filter.addOrientation(displayRotation, locked, captureOrientation); filter.addAngle(angle); transform = filter.getInverseTransform(); videoSize = filter.getOutputSize().limit(maxSize).round8(); + + try { + boolean isFlipped = captureOrientation.isFlipped(); + streamer.writeVideoSession(videoSize, isFlipped, displayRotation); + } catch (Exception e) { + } + // Ln.i("@@@@@@@"+(transform != null ? transform.toString():"Null")); + + // Ln.i("===="+captureOrientation.isFlipped()+"=="+captureOrientation.getRotation()); + // Ln.i("===="+displayInfo.getRotation()+"=="+videoSize.getWidth()+"=="+videoSize.getHeight()+"=="+locked+"=============="); } @Override 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..3c89850e 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java @@ -74,13 +74,13 @@ public class SurfaceEncoder implements AsyncProcessor { boolean headerWritten = false; do { + if (!headerWritten) { + streamer.writeVideoHeader(); + headerWritten = true; + } reset.consumeReset(); // If a capture reset was requested, it is implicitly fulfilled capture.prepare(); Size size = capture.getSize(); - if (!headerWritten) { - streamer.writeVideoHeader(size); - headerWritten = true; - } format.setInteger(MediaFormat.KEY_WIDTH, size.getWidth()); format.setInteger(MediaFormat.KEY_HEIGHT, size.getHeight());