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>
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>
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>
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>
`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>
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>
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>
`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>
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>
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>
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>
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>
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>
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>
Only an AudioCaptureException should disable the audio stream without
making scrcpy exit (it is not a fatal error).
A ConfigurationException or any other Throwable must be considered a
fatal error.
BEFORE AFTER
AudioCaptureException: non-fatal non-fatal
ConfigurationException: fatal fatal
any other Throwable: non-fatal fatal
Refs #6600 comment <https://github.com/Genymobile/scrcpy/issues/6600#issuecomment-3744934826>