816 Commits

Author SHA1 Message Date
pngocthach
8ced132538 Add support for VP8 and VP9 video encoders
Fixes #6763 <https://github.com/Genymobile/scrcpy/issues/6763>
PR #6769 <https://github.com/Genymobile/scrcpy/pull/6769>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2026-05-27 23:06:26 +02:00
Romain Vimont
f457fd4cf5 Apply encoder size constraints only after failure
The reported video encoder size constraints may be incorrect. Only apply
them if encoding fails at the requested size.

Refs #6829 <https://github.com/Genymobile/scrcpy/issues/6829>
Fixes #6848 <https://github.com/Genymobile/scrcpy/issues/6848>
PR 6859 <https://github.com/Genymobile/scrcpy/pull/6859>
2026-05-27 21:31:35 +02:00
Romain Vimont
cf237f01c2 Inline video constraints creation
This will make the following commit easier to read.

PR #6859 <https://github.com/Genymobile/scrcpy/pull/6859>
2026-05-27 21:31:35 +02:00
Romain Vimont
71c6bf4a87 Fix size constraints algorithm
The algorithm used to constrain a size according to the video
capabilities, implemented in #6766, was too simplistic: it computed the
maximum landscape size by retrieving the maximum width and its
associated maximum height (and vice versa for the maximum portrait
size).

In addition to width and height, encoders are also constrained by a
maximum surface area (in blocks). As a result, it is possible for the
maximum width to be 4096 with an associated maximum height of 512, while
the encoder still supports 1600x1200.

In that case, the previous algorithm incorrectly considered 512 to be
the absolute maximum height in landscape mode.

Instead, determine the optimal supported size, defined as the largest
size with the same aspect ratio supported by the encoder. If preserving
the aspect ratio is not required (for virtual displays), then the
dimensions derived from this optimal size can be extended.

Refs #6849 comment <https://github.com/Genymobile/scrcpy/pull/6849#issuecomment-4502114417>
Refs #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
Refs #6848 <https://github.com/Genymobile/scrcpy/issues/6848>
Fixes #6829 <https://github.com/Genymobile/scrcpy/issues/6829>
PR #6859 <https://github.com/Genymobile/scrcpy/pull/6859>
2026-05-27 21:31:35 +02:00
Romain Vimont
4954415cc3 Resize using the DPI from the local DisplayInfo
The `dpi` field is not synchronized, and the DPI to use is the one from
the latest `DisplayInfo`.

Refs #6772 comment <https://github.com/Genymobile/scrcpy/pull/6772#discussion_r3305727574>
2026-05-27 19:09:05 +02:00
Romain Vimont
83c0e6a1a2 Fix call to size.constrain()
In flex display mode, constraining the size does not require preserving
the aspect ratio.

Refs #6822 comment <https://github.com/Genymobile/scrcpy/pull/6822#discussion_r3300069201>
2026-05-26 08:01:26 +02:00
Romain Vimont
048c747cc1 Bump version to 4.0 2026-05-12 20:28:37 +02:00
Romain Vimont
d3ffab9d74 Add hacky workaround to fix Meta Quest flickering
Scrcpy captures the screen first using the `DisplayManager` API, and if
that fails, it falls back to the `SurfaceControl` API.

On the Meta Quest 3, `DisplayManager` initialization throws a
`RuntimeException` with the message:

    createVirtualDisplay failed. See logcat for error

After this, scrcpy falls back to the `SurfaceControl` API, which starts
mirroring the screen.

The problem is that although `createVirtualDisplay()` throws a
`RuntimeException`, a mirroring session was started anyway.
Consequently, the fallback via `SurfaceControl` starts a second
mirroring session to the same Surface, causing flickering.

On Meta Quest, assume that the mirroring started successfully and create
a dummy virtual display instance that wraps the surface.

Refs #5913 comment <https://github.com/Genymobile/scrcpy/issues/5913#issuecomment-3677889916>
Fixes #5913 <https://github.com/Genymobile/scrcpy/issues/5913>
2026-05-12 18:54:42 +02:00
Romain Vimont
5830dedbe4 Restore retry capture at lower resolution
The mechanism to retry capture at a lower resolution on error was
removed in favor of using video encoder capabilities instead.

However, an encoder configuration that is compatible with the declared
capabilities may still fail, either because the declared capabilities
are incorrect or because some resources are unavailable.

Restore the downsize-on-error behavior for such cases.

This reverts commit 4f97e2e30b.

Refs #2947 <https://github.com/Genymobile/scrcpy/pull/2947>
Refs #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
PR #6822 <https://github.com/Genymobile/scrcpy/pull/6822>
2026-05-11 23:06:57 +02:00
Romain Vimont
7ad637d991 Restore retry on spurious error
MediaCodec may fail spuriously, typically when stopping an encoding and
starting a new one immediately (for example on device rotation).

This was initially fixed by [1], but the fix was removed by [2], along
with the removal of the mechanism to retry capture at a lower resolution
on error.

[1]: commit 07806ba915
[2]: commit 4f97e2e30b

Refs #3693 <https://github.com/Genymobile/scrcpy/issues/3693>
Refs #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
PR #6822 <https://github.com/Genymobile/scrcpy/pull/6822>
2026-05-11 23:05:31 +02:00
Romain Vimont
f2ee5b3d06 Skip aspect ratio preservation for flex displays
The size must be constrained by the video capabilities, but unlike
fixed displays, the aspect ratio should not be preserved in order to use
the maximum available area.

Refs #6772 comment <https://github.com/Genymobile/scrcpy/pull/6772#issuecomment-4321652487>
PR #6772 <https://github.com/Genymobile/scrcpy/pull/6772>
2026-05-09 17:28:52 +02:00
Romain Vimont
2dd31b814f Ensure minimum codec size respects alignment
Make the minimum codec size respect the provided `--min-size-alignment`
value.

Refs #6766 comment <https://github.com/Genymobile/scrcpy/pull/6766#discussion_r3133194910>
PR #6772 <https://github.com/Genymobile/scrcpy/pull/6772>
2026-05-09 17:28:52 +02:00
Romain Vimont
0d73d84f84 Never increase dimensions when applying alignment
Previously, the minor dimension was rounded to the nearest multiple of
the alignment requirement when constraining size. This could result in
the dimension being increased.

Change the behavior to always round down instead, ensuring the
constrained size never grows.

This fixes a conflict with the client-side "optimal window size"
computation, which never increases dimensions. With flex displays, the
old behavior could lead to feedback loop between window and display
resizing with mismatched dimensions:

 - window  resized to 2341x1317
 - display resized to 2340x1318
 - window  resized to 2338x1317
 - display resized to 2336x1318

PR #6772 <https://github.com/Genymobile/scrcpy/pull/6772>
2026-05-09 17:28:52 +02:00
Romain Vimont
01d49a24f8 Extract align() function
PR #6772 <https://github.com/Genymobile/scrcpy/pull/6772>
2026-05-09 17:28:52 +02:00
Romain Vimont
3d78b5d8ed Flip comparison operands for readability
Refs #6772 comment <https://github.com/Genymobile/scrcpy/pull/6772#discussion_r3171106432>
PR #6772 <https://github.com/Genymobile/scrcpy/pull/6772>
2026-05-09 17:28:52 +02:00
Romain Vimont
4474d17807 Fix rotated virtual display size detection
The physical size of the virtual display does not change when the
display is rotated, although the reported display size does.

Refs #6772 comment <https://github.com/Genymobile/scrcpy/pull/6772#pullrequestreview-4238019023>
PR #6772 <https://github.com/Genymobile/scrcpy/pull/6772>
2026-05-09 17:28:52 +02:00
Romain Vimont
9c4d2bbfc2 Add resizable virtual display feature
Introduce `--flex-display` (or `-x`) to continuously resize the virtual
display to match the window.

Fixes #6632 <https://github.com/Genymobile/scrcpy/issues/6632>
PR #6772 <https://github.com/Genymobile/scrcpy/pull/6772>
2026-05-09 17:28:52 +02:00
Romain Vimont
9e0d2a1bc9 Signal client resize in session packets
So far, scrcpy always resized the window whenever a frame with a new
size was received. However, with the upcoming "flex display" feature,
the size of the virtual display can change either on its own (e.g.,
due to app rotation) or as a result of a client window resize.

Track the cause of each resize and signal it in the session metadata.

Resize the window only if the change was not triggered by a client
request to prevent resize loops and stuttering.

PR #6772 <https://github.com/Genymobile/scrcpy/pull/6772>
2026-05-09 17:28:52 +02:00
Romain Vimont
51a680324c Provide reason for capture reset
Add flags to indicate why a capture was reset.

This paves the way for properly handling virtual display resize
requests.

PR #6772 <https://github.com/Genymobile/scrcpy/pull/6772>
2026-05-09 17:28:52 +02:00
Romain Vimont
1136def6a9 Refactor CaptureReset into CaptureControl
Expose `CaptureControl` directly in `SurfaceCapture` to remove a layer
of indirection (`CaptureListener`). This reduces boilerplate.

PR #6772 <https://github.com/Genymobile/scrcpy/pull/6772>
2026-05-09 17:28:52 +02:00
Romain Vimont
1495dae0dc Add RESIZE_DISPLAY control message
Add a new control message type to request a resize of the virtual
display.

PR #6772 <https://github.com/Genymobile/scrcpy/pull/6772>
2026-05-09 17:28:52 +02:00
Romain Vimont
0e5ff52ecd Log DisplayMonitor callback errors
Any exception thrown during a DisplayListener or a WindowListener
callback was silently ignored.

Refs #6772 comment <https://github.com/Genymobile/scrcpy/pull/6772#issuecomment-4333306161>
PR #6772 <https://github.com/Genymobile/scrcpy/pull/6772>
2026-05-09 17:28:52 +02:00
Romain Vimont
4b60bf0bda Forward video constraints to subclasses directly
Make the abstract superclass `SurfaceCapture` forward the
`VideoConstraints` instance directly via the `init()` method, instead of
storing it and exposing it via `getVideoConstraints().

This will let implementations handle it as they wish, particularly with
regard to synchronization.

PR #6772 <https://github.com/Genymobile/scrcpy/pull/6772>
2026-05-09 17:28:52 +02:00
Romain Vimont
5b220515c6 Simplify OpenGLRunner shutdown
Merge `quit()` and `join()` into a single `shutdown()`.

PR #6794 <https://github.com/Genymobile/scrcpy/pull/6794>
2026-04-30 12:06:00 +02:00
Romain Vimont
5284b1ecb7 Fix OpenGL runner shutdown deadlock
`OpenGLRunner.stopAndRelease()` posts work to its internal
`HandlerThread`, so the thread must remain alive until the task
completes. Otherwise, the method may never terminate.

However, `OpenGLRunner.quit()` was called before `asyncProcessor.join()`
(in particular before `SurfaceEncoder.join()`), allowing the runner to
be shut down while `SurfaceEncoder` was still running. In some cases,
`capture.stop()`, which calls `glRunner.stopAndRelease()`, was invoked
after the `HandlerThread` had already been quit, causing a deadlock.
This led to server hangs and prevented a graceful shutdown.

Fix proper ordering of shutdown and joins so the OpenGL runner stops
safely.

PR #6794 <https://github.com/Genymobile/scrcpy/pull/6794>
2026-04-30 12:06:00 +02:00
Romain Vimont
9b2498c852 Add --keep-active
An an option to simulate user activity to prevent the screen from
turning off due to inactivity.

Fixes #6787 <https://github.com/Genymobile/scrcpy/issues/6787>
PR #6792 <https://github.com/Genymobile/scrcpy/pull/6792>
2026-04-27 09:26:07 +02:00
Romain Vimont
b48feed0a0 Fix turning virtual display on via right-click
Since Android 14, it is possible to detect whether a virtual display is
on.

On right-click, turn the virtual display on if it is off (Android 14+
only).

PR #6788 <https://github.com/Genymobile/scrcpy/pull/6788>
2026-04-27 09:15:13 +02:00
Romain Vimont
6034110140 Fix build_without_gradle script
Changes missing from b38ba2f687.
2026-04-16 21:45:28 +02:00
Romain Vimont
266e2eaf14 Align the virtual display size
When the virtual display size is not aligned, a resize filter may be
inserted to compensate for small dimension mismatches, increasing
processing and resulting in a blurry image.

PR #6771 <https://github.com/Genymobile/scrcpy/pull/6771>
2026-04-16 19:40:21 +02:00
Romain Vimont
965d0e6856 Fix comment wording
For clarity and grammar.
2026-04-16 19:15:22 +02:00
Romain Vimont
03878083fb Reset capture on rotation (fix square displays)
`DisplayMonitor` previously only triggered a capture reset when the
display size changed. In most cases, rotation also changes dimensions,
so the behavior was correct… except for square displays where width and
height remain unchanged.

However, rotation still requires a capture reset even when dimensions do
not change, to ensure the orientation filter is applied so virtual
displays are rendered correctly.

To reproduce the issue:

    scrcpy --new-display=600x600 --start-app=com.android.settings

Then press Alt+r to rotate the Settings app.

PR #6770 <https://github.com/Genymobile/scrcpy/pull/6770>
2026-04-16 19:06:27 +02:00
Romain Vimont
b38ba2f687 Reorganize server packages
Move existing classes into newly created `display` and `model` packages.
2026-04-15 10:01:27 +02:00
Romain Vimont
69578f1200 Remove overwritten assignment
The `videoSize` field is always reassigned to `filter.getOutputSize()`.
2026-04-14 22:56:28 +02:00
Romain Vimont
fe9450afcc Remove unnecessary synchronization
The `videoSize` field is never written while holding the mutex, and is
only accessed from the same thread.
2026-04-14 22:56:28 +02:00
Romain Vimont
66005e8889 Respect encoder minimum size constraint
Encoders require a minimum video size.

Use video capabilities to constrain a given size by the declared minimum
size of the selected encoder.

Contrary to the maximum size constraints (but like the alignment
constraint), use the same value in both directions for simplicity and so
that rotating the device does not change the shape of the video.

PR #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
2026-04-14 22:52:10 +02:00
Romain Vimont
33b1bc6209 Respect encoder maximum size constraint
Encoders cannot encode at any resolution.

Use video capabilities to constrain a given size by the limits of the
selected encoder.

These video capabilities describe the range of supported widths and
heights, as well as the supported heights for a given width (and
vice-versa). Use this information to compute the maximum portrait size
and the maximum landscape size.

PR #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
2026-04-14 22:51:48 +02:00
Romain Vimont
809718ed25 Extract method to create VideoConstraints
As more constraints are added, this avoids polluting the
`streamCapture()` method.

PR #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
2026-04-14 22:51:36 +02:00
Romain Vimont
a1d1d95404 Move max size into VideoConstraints
Make the requested max size part of `VideoConstraints`.

PR #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
2026-04-14 22:51:02 +02:00
Romain Vimont
5b6e2cfdd4 Introduce VideoConstraints
Group video constraints into a dedicated class. For now it only contains
the `alignment` field; additional constraints will be added in further
commits.

PR #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
2026-04-14 22:50:36 +02:00
Romain Vimont
3c3cfe8cc6 Constraint size and alignment simultaneously
Previously, the size was scaled to fit the requested maximum size and
then aligned. If the maximum size was not a multiple of the alignment,
the resulting size was suboptimal as it preserved the aspect ratio less
accurately.

This also prepares for additional video constraints.

PR #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
2026-04-14 22:50:28 +02:00
Romain Vimont
4f97e2e30b Disable retry capture at lower resolution
A mechanism was introduced to retry capture at a lower resolution to
support devices unable to encode at the device screen resolution.

While useful, this approach is inherently limited and will not be able
to handle the dynamic resizing required for resizable virtual displays.

Disable this mechanism entirely. Further commits will add support for
adjusting the size in advance according to video encoder capabilities.

Refs #2947 <https://github.com/Genymobile/scrcpy/pull/2947>
PR #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
2026-04-14 22:50:28 +02:00
Romain Vimont
3b00032a01 Make field final
The `displayImePolicy` field may be `final`.

PR #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
2026-04-14 22:50:22 +02:00
Romain Vimont
f54cf8b336 Move MediaFormat creation
For code clarity.

PR #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
2026-04-14 22:50:03 +02:00
Romain Vimont
ae13c77c5e Add option to force size alignment
Add --min-size-alignment to force a minimal size alignment.

This is a power-of-2 value (1, 2, 4, 8 or 16) that the video width and
height must be multiples of.

The actual alignment will be the maximum of this value and the video
codec's alignment requirement.

PR #6746 <https://github.com/Genymobile/scrcpy/pull/6746>
2026-04-07 19:47:11 +02:00
Romain Vimont
ae8ecb1d0e Use optimal size alignment
The video was always constrained to use a size that is a multiple of 8.
This was sometimes not necessary (recent codecs only require a video
size that is a multiple of 2 or even 1) and sometimes insufficient (some
codecs require a size that is multiple of 16).

Use the size alignment required by the codec.

Fixes #4949 <https://github.com/Genymobile/scrcpy/issues/4949>
Fixes #6236 <https://github.com/Genymobile/scrcpy/issues/6236>
PR #6746 <https://github.com/Genymobile/scrcpy/pull/6746>
2026-04-07 19:47:00 +02:00
Romain Vimont
df91514112 Fix camera failure handling
The camera capture must be closed on error (isClosed() returns the value
of the disconnected flag).
2026-03-31 20:03:46 +02:00
Romain Vimont
a6c16180ee Fix display size monitor synchronization
Do not unlock the mutex between reading and writing to
sessionDisplaySize.
2026-03-31 20:03:44 +02:00
Romain Vimont
57a40917d4 Remove trailing comma
Fix typo.
2026-03-31 19:54:46 +02:00
Romain Vimont
edc81b4a1c Do not fallback to main display
If the virtual display is not initialized yet, do not send events to the
main display.
2026-03-31 19:54:13 +02:00
Romain Vimont
1c68d79eea Upgrade AGP (9.1.0) and Gradle (9.3.1) 2026-03-24 20:56:19 +01:00