The first frames are typically received and decoded with more delay than
the others, causing a wrong slope estimation on start.
To compensate, assume an initial slope of 1, then progressively use the
estimated slope.
To minimize latency (at the cost of jitter), scrcpy always displays a
frame as soon as it available, without waiting.
However, when recording (--record), it still writes the captured
timestamps to the output file, so that the recorded file can be played
correctly without jitter.
Some real-time use cases might benefit from adding a small latency to
compensate for jitter too. For example, few tens of seconds of latency
for live-streaming are not important, but jitter is noticeable.
Therefore, implement a buffering mechanism (disabled by default) to add
a configurable latency delay.
PR #2417 <https://github.com/Genymobile/scrcpy/issues/2417>
Currently, a frame is available to the consumer as soon as it is pushed
by the producer (which can detect if the previous frame is skipped).
Notify the new frames (and frame skipped) via callbacks instead.
This paves the way to add (optional) buffering, which will introduce a
delay between the time when the frame is produced and the time it is
available to be consumed.
The current video buffer only stores one pending frame.
In order to add a new buffering feature, move this part to a separate
"frame buffer". Keep the video_buffer, which currently delegates all its
calls to the frame_buffer.
To fix a data race, commit 5caeab5f6d
called video_buffer_push() and video_buffer_consume() under the
v4l2_sink lock.
Instead, use the previous_skipped indication (initialized with video
buffer locked) to lock only for protecting the has_frame flag.
This enables the possibility for the video_buffer to notify new frames
via callbacks without lock inversion issues.
The function sc_cond_timedwait() accepted a parameter representing the
max duration to wait, because it internally uses SDL_CondWaitTimeout().
Instead, accept a deadline, to be consistent with
pthread_cond_timedwait().
The v4l2_sink implementation directly read the internal video_buffer
field "pending_frame_consumed", which is protected by the internal
video_buffer mutex. But this mutex was not locked, so reads were racy.
Lock using the v4l2_sink mutex in addition, and use a separate field to
avoid depending on the video_buffer internal data.
Commit 21d206f360 added mutex assertions.
However, the "locker" variable to trace the locker thread id was read
and written by several threads without any protection, so it was racy.
Reported by TSAN.
The options --no-display and --no-control are independent.
The controller was not initialized when no display was requested,
because it was assumed that no control could occur without display. But
that's not true (anymore): for example, it is possible to pass
--turn-screen-off.
Fixes#2426 <https://github.com/Genymobile/scrcpy/issues/2426>
Mouse motion events were forwarded as soon as any mouse button was
pressed.
Instead, only consider left-click (and also middle-click and right-click
if --forward-all-clicks is enabled).
Change the default push target from /sdcard/ to /sdcard/Download/.
Pushing to the root of /sdcard/ is not very convenient, many apps do not
expose its content directly.
It can still be changed by --push-target.
PR #2384 <https://github.com/Genymobile/scrcpy/pull/2384>
When removing the black borders (by double-clicking on them, or by
pressing MOD+w), the window is resized to fit the device screen, but its
top-left position was left unchanged.
Instead, move the window so that the new window area is at the center of
the old window area.
Refs #2387 <https://github.com/Genymobile/scrcpy/issues/2387>
It should not be necessary, since screen_render() is called just after
on SDL_WINDOWEVENT_EXPOSED, but in practice the window content might not
be correctly displayed on restored if a rotation occurred while
minimized.
Note that calling screen_render() twice in a row on
SDL_WINDOWEVENT_EXPOSED also "fixes" the issue.
From FFmpeg/doc/APIchanges:
2021-03-17 - f7db77bd87 - lavc 58.133.100 - codec.h
Deprecated av_init_packet(). Once removed, sizeof(AVPacket) will
no longer be a part of the public ABI.
Refs #2302 <https://github.com/Genymobile/scrcpy/issues/2302>
From FFmpeg/doc/APIchanges:
2021-03-17 - f7db77bd87 - lavc 58.133.100 - codec.h
Deprecated av_init_packet(). Once removed, sizeof(AVPacket) will
no longer be a part of the public ABI.
Refs #2302 <https://github.com/Genymobile/scrcpy/issues/2302>
From FFmpeg/doc/APIchanges:
2021-03-17 - f7db77bd87 - lavc 58.133.100 - codec.h
Deprecated av_init_packet(). Once removed, sizeof(AVPacket) will
no longer be a part of the public ABI.
Refs #2302 <https://github.com/Genymobile/scrcpy/issues/2302>
From FFmpeg/doc/APIchanges:
2021-03-17 - f7db77bd87 - lavc 58.133.100 - codec.h
Deprecated av_init_packet(). Once removed, sizeof(AVPacket) will
no longer be a part of the public ABI.
Remove the has_pending boolean, which can be replaced by:
stream->pending != NULL
Refs #2302 <https://github.com/Genymobile/scrcpy/issues/2302>
The argument for option --lock-video-orientation has been made optional
by 5af9d0ee0f.
With getopt_long(), contrary to mandatory arguments, optional arguments
must be given with a '=':
--lock-video-orientation 2 # wrong, parse error
--lock-video-orientation=2 # correct
The input manager was partially initialized statically, but a call to
input_manager_init() was needed anyway, so initialize all the fields
from the "constructor".
This is consistent with the initialization of the other structs.
The frame can be unref immediately after it is pushed to the frame
sinks.
It was not really a memory leak because the frame was unref every time
by avcodec_receive_frame() (and freed on close), but a reference was
unnecessarily kept for too long.
Add a new mode to the --lock-video-orientation option, to lock the
initial orientation of the device.
This avoids to pass an explicit value (0, 1, 2 or 3) and think about
which is the right one.
The screen may not be destroyed immediately on close to avoid undefined
behavior, because it may still receive events from the decoder.
But the visual window must still be closed immediately.
The destruction order is important, but tricky, because the screen is
open/close by the decoder, but destroyed by scrcpy.c on the main thread.
Add assertions to guarantee that the screen is not destroyed before
being closed.
The video buffer is now an internal detail of the screen component.
Since the screen is plugged to the decoder via the frame sink trait, the
decoder does not access to the video buffer anymore.
The fact that the recorder uses a separate thread is an internal detail,
so the functions _start(), _stop() and _join() should not be exposed.
Instead, start the thread on _open() and _stop()+_join() on close().
This paves the way to expose the recorder as a packet sink trait.
The video buffer took ownership of the producer frame (so that it could
swap frames quickly).
In order to support multiple sinks plugged to the decoder, the decoded
frame must not be consumed by the display video buffer.
Therefore, move the producer and consumer frames out of the video
buffer, and use FFmpeg AVFrame refcounting to share ownership while
avoiding copies.
This flag forced the decoder to wait for the previous frame to be
consumed by the display.
It was initially implemented as a compilation flag for testing, not
intended to be exposed at runtime. But to remove ifdefs and to allow
users to test this flag easily, it had finally been exposed by commit
ebccb9f6cc.
In practice, it turned out to be useless: it had no practical impact,
and it did not solve or mitigate any performance issues causing frame
skipping.
But that added some complexity to the codebase: it required an
additional condition variable, and made video buffer calls possibly
blocking, which in turn required code to interrupt it on exit.
To prepare support for multiple sinks plugged to the decoder (display
and v4l2 for example), the blocking call used for pacing the decoder
output becomes unacceptable, so just remove this useless "feature".
Double-click on extra mouse button to open the settings panel (a
single-click opens the notification panel).
This is consistent with the keyboard shortcut MOD+n+n.
PR #2264 <https://github.com/Genymobile/scrcpy/pull/2264>
Signed-off-by: Romain Vimont <rom@rom1v.com>