Compare commits
7 Commits
reschange.
...
display_ma
Author | SHA1 | Date | |
---|---|---|---|
fdc58722b3 | |||
5a6b8310ca | |||
c6ff78f414 | |||
40f2560d98 | |||
26aa28c998 | |||
ef79fcbbd2 | |||
bd9292931e |
@ -1,4 +1,8 @@
|
|||||||
# scrcpy (v2.3)
|
**This GitHub repo (<https://github.com/Genymobile/scrcpy>) is the only official
|
||||||
|
source for the project. Do not download releases from random websites, even if
|
||||||
|
their name contains `scrcpy`.**
|
||||||
|
|
||||||
|
# scrcpy (v2.3.1)
|
||||||
|
|
||||||
<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
|
<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ BEGIN
|
|||||||
VALUE "LegalCopyright", "Romain Vimont, Genymobile"
|
VALUE "LegalCopyright", "Romain Vimont, Genymobile"
|
||||||
VALUE "OriginalFilename", "scrcpy.exe"
|
VALUE "OriginalFilename", "scrcpy.exe"
|
||||||
VALUE "ProductName", "scrcpy"
|
VALUE "ProductName", "scrcpy"
|
||||||
VALUE "ProductVersion", "2.3"
|
VALUE "ProductVersion", "2.3.1"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -227,8 +227,9 @@ run_demuxer(void *data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Config packets must be merged with the next non-config packet only for
|
// Config packets must be merged with the next non-config packet only for
|
||||||
// video streams
|
// H.26x
|
||||||
bool must_merge_config_packet = codec->type == AVMEDIA_TYPE_VIDEO;
|
bool must_merge_config_packet = raw_codec_id == SC_CODEC_ID_H264
|
||||||
|
|| raw_codec_id == SC_CODEC_ID_H265;
|
||||||
|
|
||||||
struct sc_packet_merger merger;
|
struct sc_packet_merger merger;
|
||||||
|
|
||||||
|
@ -233,10 +233,10 @@ install` must be run as root)._
|
|||||||
|
|
||||||
#### Option 2: Use prebuilt server
|
#### Option 2: Use prebuilt server
|
||||||
|
|
||||||
- [`scrcpy-server-v2.3`][direct-scrcpy-server]
|
- [`scrcpy-server-v2.3.1`][direct-scrcpy-server]
|
||||||
<sub>SHA-256: `8daed514d7796fca6987dc973e201bd15ba51d0f7258973dec92d9ded00dbd5f`</sub>
|
<sub>SHA-256: `f6814822fc308a7a532f253485c9038183c6296a6c5df470a9e383b4f8e7605b`</sub>
|
||||||
|
|
||||||
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v2.3/scrcpy-server-v2.3
|
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v2.3.1/scrcpy-server-v2.3.1
|
||||||
|
|
||||||
Download the prebuilt server somewhere, and specify its path during the Meson
|
Download the prebuilt server somewhere, and specify its path during the Meson
|
||||||
configuration:
|
configuration:
|
||||||
|
@ -21,6 +21,13 @@ This will create a new video device in `/dev/videoN`, where `N` is an integer
|
|||||||
(more [options](https://github.com/umlaeute/v4l2loopback#options) are available
|
(more [options](https://github.com/umlaeute/v4l2loopback#options) are available
|
||||||
to create several devices or devices with specific IDs).
|
to create several devices or devices with specific IDs).
|
||||||
|
|
||||||
|
If you encounter problems detecting your device with Chrome/WebRTC, you can try
|
||||||
|
`exclusive_caps` mode:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo modprobe v4l2loopback exclusive_caps=1
|
||||||
|
```
|
||||||
|
|
||||||
To list the enabled devices:
|
To list the enabled devices:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
|
|
||||||
Download the [latest release]:
|
Download the [latest release]:
|
||||||
|
|
||||||
- [`scrcpy-win64-v2.3.zip`][direct-win64] (64-bit)
|
- [`scrcpy-win64-v2.3.1.zip`][direct-win64] (64-bit)
|
||||||
<sub>SHA-256: `a2fdd2733bd337261bb493e77d990078a23e7a40149dd0c0dc45725c929a715f`</sub>
|
<sub>SHA-256: `f1f78ac98214078425804e524a1bed515b9d4b8a05b78d210a4ced2b910b262d`</sub>
|
||||||
- [`scrcpy-win32-v2.3.zip`][direct-win32] (32-bit)
|
- [`scrcpy-win32-v2.3.1.zip`][direct-win32] (32-bit)
|
||||||
<sub>SHA-256: `dfdbb69a872d717aed5bcfe352e571564c357fdb7a9c172d69f450fdf5154a0a`</sub>
|
<sub>SHA-256: `5dffc2d432e9b8b5b0e16f12e71428c37c70d9124cfbe7620df0b41b7efe91ff`</sub>
|
||||||
|
|
||||||
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
||||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v2.3/scrcpy-win64-v2.3.zip
|
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v2.3.1/scrcpy-win64-v2.3.1.zip
|
||||||
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v2.3/scrcpy-win32-v2.3.zip
|
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v2.3.1/scrcpy-win32-v2.3.1.zip
|
||||||
|
|
||||||
and extract it.
|
and extract it.
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
BUILDDIR=build-auto
|
BUILDDIR=build-auto
|
||||||
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v2.3/scrcpy-server-v2.3
|
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v2.3.1/scrcpy-server-v2.3.1
|
||||||
PREBUILT_SERVER_SHA256=8daed514d7796fca6987dc973e201bd15ba51d0f7258973dec92d9ded00dbd5f
|
PREBUILT_SERVER_SHA256=f6814822fc308a7a532f253485c9038183c6296a6c5df470a9e383b4f8e7605b
|
||||||
|
|
||||||
echo "[scrcpy] Downloading prebuilt server..."
|
echo "[scrcpy] Downloading prebuilt server..."
|
||||||
wget "$PREBUILT_SERVER_URL" -O scrcpy-server
|
wget "$PREBUILT_SERVER_URL" -O scrcpy-server
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
project('scrcpy', 'c',
|
project('scrcpy', 'c',
|
||||||
version: '2.3',
|
version: '2.3.1',
|
||||||
meson_version: '>= 0.48',
|
meson_version: '>= 0.48',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c11',
|
'c_std=c11',
|
||||||
|
@ -7,8 +7,8 @@ android {
|
|||||||
applicationId "com.genymobile.scrcpy"
|
applicationId "com.genymobile.scrcpy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 34
|
targetSdkVersion 34
|
||||||
versionCode 20300
|
versionCode 20301
|
||||||
versionName "2.3"
|
versionName "2.3.1"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
SCRCPY_DEBUG=false
|
SCRCPY_DEBUG=false
|
||||||
SCRCPY_VERSION_NAME=2.3
|
SCRCPY_VERSION_NAME=2.3.1
|
||||||
|
|
||||||
PLATFORM=${ANDROID_PLATFORM:-34}
|
PLATFORM=${ANDROID_PLATFORM:-34}
|
||||||
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-34.0.0}
|
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-34.0.0}
|
||||||
|
@ -164,6 +164,10 @@ public final class Device {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getDisplayId() {
|
||||||
|
return displayId;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void setMaxSize(int newMaxSize) {
|
public synchronized void setMaxSize(int newMaxSize) {
|
||||||
maxSize = newMaxSize;
|
maxSize = newMaxSize;
|
||||||
screenInfo = ScreenInfo.computeScreenInfo(screenInfo.getReverseVideoRotation(), deviceSize, crop, newMaxSize, lockVideoOrientation);
|
screenInfo = ScreenInfo.computeScreenInfo(screenInfo.getReverseVideoRotation(), deviceSize, crop, newMaxSize, lockVideoOrientation);
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package com.genymobile.scrcpy;
|
package com.genymobile.scrcpy;
|
||||||
|
|
||||||
|
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
||||||
import com.genymobile.scrcpy.wrappers.SurfaceControl;
|
import com.genymobile.scrcpy.wrappers.SurfaceControl;
|
||||||
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.hardware.display.VirtualDisplay;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
@ -11,6 +13,7 @@ public class ScreenCapture extends SurfaceCapture implements Device.RotationList
|
|||||||
|
|
||||||
private final Device device;
|
private final Device device;
|
||||||
private IBinder display;
|
private IBinder display;
|
||||||
|
private VirtualDisplay virtualDisplay;
|
||||||
|
|
||||||
public ScreenCapture(Device device) {
|
public ScreenCapture(Device device) {
|
||||||
this.device = device;
|
this.device = device;
|
||||||
@ -34,9 +37,29 @@ public class ScreenCapture extends SurfaceCapture implements Device.RotationList
|
|||||||
|
|
||||||
if (display != null) {
|
if (display != null) {
|
||||||
SurfaceControl.destroyDisplay(display);
|
SurfaceControl.destroyDisplay(display);
|
||||||
|
display = null;
|
||||||
|
}
|
||||||
|
if (virtualDisplay != null) {
|
||||||
|
virtualDisplay.release();
|
||||||
|
virtualDisplay = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
display = createDisplay();
|
||||||
|
setDisplaySurface(display, surface, videoRotation, contentRect, unlockedVideoRect, layerStack);
|
||||||
|
Ln.d("Display: using SurfaceControl API");
|
||||||
|
} catch (Exception surfaceControlException) {
|
||||||
|
Rect videoRect = screenInfo.getVideoSize().toRect();
|
||||||
|
try {
|
||||||
|
virtualDisplay = ServiceManager.getDisplayManager()
|
||||||
|
.createVirtualDisplay("scrcpy", videoRect.width(), videoRect.height(), device.getDisplayId(), surface);
|
||||||
|
Ln.d("Display: using DisplayManager API");
|
||||||
|
} catch (Exception displayManagerException) {
|
||||||
|
Ln.e("Could not create display using SurfaceControl", surfaceControlException);
|
||||||
|
Ln.e("Could not create display using DisplayManager", displayManagerException);
|
||||||
|
throw new AssertionError("Could not create display");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
display = createDisplay();
|
|
||||||
setDisplaySurface(display, surface, videoRotation, contentRect, unlockedVideoRect, layerStack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -69,7 +92,7 @@ public class ScreenCapture extends SurfaceCapture implements Device.RotationList
|
|||||||
requestReset();
|
requestReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IBinder createDisplay() {
|
private static IBinder createDisplay() throws Exception {
|
||||||
// Since Android 12 (preview), secure displays could not be created with shell permissions anymore.
|
// Since Android 12 (preview), secure displays could not be created with shell permissions anymore.
|
||||||
// On Android 12 preview, SDK_INT is still R (not S), but CODENAME is "S".
|
// On Android 12 preview, SDK_INT is still R (not S), but CODENAME is "S".
|
||||||
boolean secure = Build.VERSION.SDK_INT < Build.VERSION_CODES.R || (Build.VERSION.SDK_INT == Build.VERSION_CODES.R && !"S".equals(
|
boolean secure = Build.VERSION.SDK_INT < Build.VERSION_CODES.R || (Build.VERSION.SDK_INT == Build.VERSION_CODES.R && !"S".equals(
|
||||||
|
@ -5,14 +5,18 @@ import com.genymobile.scrcpy.DisplayInfo;
|
|||||||
import com.genymobile.scrcpy.Ln;
|
import com.genymobile.scrcpy.Ln;
|
||||||
import com.genymobile.scrcpy.Size;
|
import com.genymobile.scrcpy.Size;
|
||||||
|
|
||||||
|
import android.hardware.display.VirtualDisplay;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
|
import android.view.Surface;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public final class DisplayManager {
|
public final class DisplayManager {
|
||||||
private final Object manager; // instance of hidden class android.hardware.display.DisplayManagerGlobal
|
private final Object manager; // instance of hidden class android.hardware.display.DisplayManagerGlobal
|
||||||
|
private Method createVirtualDisplayMethod;
|
||||||
|
|
||||||
public DisplayManager(Object manager) {
|
public DisplayManager(Object manager) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
@ -94,4 +98,17 @@ public final class DisplayManager {
|
|||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Method getCreateVirtualDisplayMethod() throws NoSuchMethodException {
|
||||||
|
if (createVirtualDisplayMethod == null) {
|
||||||
|
createVirtualDisplayMethod = android.hardware.display.DisplayManager.class
|
||||||
|
.getMethod("createVirtualDisplay", String.class, int.class, int.class, int.class, Surface.class);
|
||||||
|
}
|
||||||
|
return createVirtualDisplayMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VirtualDisplay createVirtualDisplay(String name, int width, int height, int displayIdToMirror, Surface surface) throws Exception {
|
||||||
|
Method method = getCreateVirtualDisplayMethod();
|
||||||
|
return (VirtualDisplay) method.invoke(null, name, width, height, displayIdToMirror, surface);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,12 +78,8 @@ public final class SurfaceControl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IBinder createDisplay(String name, boolean secure) {
|
public static IBinder createDisplay(String name, boolean secure) throws Exception {
|
||||||
try {
|
return (IBinder) CLASS.getMethod("createDisplay", String.class, boolean.class).invoke(null, name, secure);
|
||||||
return (IBinder) CLASS.getMethod("createDisplay", String.class, boolean.class).invoke(null, name, secure);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Method getGetBuiltInDisplayMethod() throws NoSuchMethodException {
|
private static Method getGetBuiltInDisplayMethod() throws NoSuchMethodException {
|
||||||
|
Reference in New Issue
Block a user