Add an option to disable the following flag for virtual displays:
DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
Some devices render a broken UI when this flag is enabled.
Fixes#5494 <https://github.com/Genymobile/scrcpy/issues/5494>
If no size is provided with --new-display, the main display size is
used. But the actual size depended on the current device orientation.
To make it deterministic, use the size of the natural device orientation
(portrait for phones, landscape for tablets).
PR #5455 <https://github.com/Genymobile/scrcpy/pull/5455>
On rotation, it is expected that many successive events are ignored due
to size mismatch, when an event was generated from the mirroring window
having the old size, but was received on the device with the new size
(especially since mouse hover events are forwarded).
Do not flood the console with warnings.
PR #5455 <https://github.com/Genymobile/scrcpy/pull/5455>
Deprecate --lock-video-orientation in favor of a more general option
--capture-orientation, which supports all possible orientations
(0, 90, 180, 270, flip0, flip90, flip180, flip270), and a "locked" flag
via a '@' prefix.
All the old "locked video orientations" are supported:
- --lock-video-orientation -> --capture-orientation=@
- --lock-video-orientation=0 -> --capture-orientation=@0
- --lock-video-orientation=90 -> --capture-orientation=@90
- --lock-video-orientation=180 -> --capture-orientation=@180
- --lock-video-orientation=270 -> --capture-orientation=@270
In addition, --capture-orientation can rotate/flip the display without
locking, so that it follows the physical device rotation.
For example:
scrcpy --capture-orientation=flip90
always flips and rotates the capture by 90° clockwise.
The arguments are consistent with --display-orientation and
--record-orientation and --orientation (which provide separate
client-side orientation settings).
Refs #4011 <https://github.com/Genymobile/scrcpy/issues/4011>
PR #5455 <https://github.com/Genymobile/scrcpy/pull/5455>
On Android 14, DisplayListener may be broken (it never sends events).
This is fixed in recent Android 14 upgrades, but we can't really detect
it directly.
As a workaround, a RotationWatcher and DisplayFoldListener were
registered as a fallback, until a first "display changed" event was
triggered.
To simplify, on Android 14, register a DisplayWindowListener (introduced
in Android 11) to listen to configuration changes instead.
Refs #5455 comment <https://github.com/Genymobile/scrcpy/pull/5455#issuecomment-2481302084>
PR #5455 <https://github.com/Genymobile/scrcpy/pull/5455>
Co-authored-by: Romain Vimont <rom@rom1v.com>
Signed-off-by: Romain Vimont <rom@rom1v.com>
Detecting display size changes is not straightforward:
- from a DisplayListener, "display changed" events are received, but
this does not imply that the size has changed (it must be checked);
- on Android 14 (see e26bdb07a2),
"display changed" events are not received on some versions, so as a
fallback, a RotationWatcher and a DisplayFoldListener are registered,
but unregistered as soon as a "display changed" event is actually
received, which means that the problem is fixed.
Extract a "display size monitor" to share the code between screen
capture and virtual display capture.
PR #5455 <https://github.com/Genymobile/scrcpy/pull/5455>
Expose two methods on Size directly:
- limit() to downscale a size;
- round8() to round both dimensions to multiples of 8.
This will allow removing ScreenInfo completely.
PR #5455 <https://github.com/Genymobile/scrcpy/pull/5455>
Introduce several key components to perform OpenGL filters:
- OpenGLRunner: a tool for running a filter to be rendered to a Surface
from an OpenGL-dedicated thread
- OpenGLFilter: a simple OpenGL filter API
- AffineOpenGLFilter: a generic OpenGL implementation to apply any 2D
affine transform
- AffineMatrix: an affine transform matrix, with helpers to build
matrices from semantic transformations (rotate, scale, translate…)
PR #5455 <https://github.com/Genymobile/scrcpy/pull/5455>
If a new display is set, force options.getDisplayId() to return
Device.DISPLAY_ID_NONE, to avoid any confusion between a local displayId
and options.getDisplayId().
All options were configured dynamically by sending a single byte to an
output stream. But in practice, only the power mode must be changed
dynamically, the others are configured once on start.
For simplicity, pass the value of static options as command line
arguments, and handle dynamic options in a loop only from a separate
thread once the clean up process is started.
This will allow to easily add cleanup options with values which do not
fit in 1 byte.
Also handle the clean up thread (and the loading of initial settings
values) from the CleanUp class, to expose a simpler clean up API.
Refs 9efa162949
PR #5447 <https://github.com/Genymobile/scrcpy/pull/5447>
A call to swr_set_compensation() configures the resampler to drop or
duplicate "diff" samples over an interval of "distance" samples.
If the function is not called again, then after "distance" samples, no
more compensation will be applied. So it must always be called, even if
the new computed diff value happens to be the same as the previous one.
In practice, it is unlikely that the diff value is exactly the same
every second, except when it is actively clamped (to 2% of the sample
rate).
Reset video capture/encoding on MOD+Shift+r.
Like on device rotation, this starts a new encoding session which
produces a video stream starting by a key frame.
PR #5432 <https://github.com/Genymobile/scrcpy/pull/5432>
When the MediaCodec input is a Surface, no EOS (end-of-stream) will
never occur automatically: it may only be triggered manually by
MediaCodec.signalEndOfInputStream().
Use this signal to interrupt the blocking call to dequeueOutputBuffer()
immediately on reset, without waiting for the next frame to be dequeued.
PR #5432 <https://github.com/Genymobile/scrcpy/pull/5432>
When the capture source becomes "invalid" (because the display size
changes for example), a reset request is performed to restart the
encoder.
The reset state was stored in SurfaceCapture. The capture implementation
set the flag, and the encoder consumed it.
However, this mechanism did not allow a reset request to _interrupt_ the
encoder, which may be waiting on a blocking call (until a new frame is
produced).
To be able to interrupt the encoder, a reset request must not only set a
flag, but run a callback provided by the encoder. For that purpose,
introduce the CaptureListener interface, which is notified by the
SurfaceCapture implementation whenever the capture is invalidated.
For now, the listener implementation just set a flag as before, so the
behavior is unchanged. It lays the groundwork for the next commits.
PR #5432 <https://github.com/Genymobile/scrcpy/pull/5432>
While moving code, commit 874eaec487 added
a condition `if (displayId == 0)` to register a rotation watcher,
without good reasons.
This condition was kept when the rotation watcher was moved to a
fallback in e26bdb07a2.
Note: use `git show -b` to show this commit ignoring whitespace changes.
Refs #5428 <https://github.com/Genymobile/scrcpy/issues/5428>