There was a frame sink trait, implemented by components able to receive
AVFrames, but each frame source had to manually send to frame sinks.
In order to mutualise sink management, add a frame sink trait.
There was a packet sink trait, implemented by components able to
receive AVPackets, but each packet source had to manually send to packet
sinks.
In order to mutualise sink management, add a packet source trait.
A video buffer had 2 responsibilities:
- handle the frame delaying mechanism (queuing packets and pushing them
after the expected delay);
- keep only the most recent frame (using a sc_frame_buffer).
In order to reuse only the frame delaying mechanism, extract it to a
separate component, sc_delay_buffer.
The video_buffer thread clears the queue once it is stopped, but new
frames might still be pushed asynchronously.
To avoid the problem, do not push any frame once the video_buffer is
stopped.
The packets queued for buffering were wrapped in a dynamically allocated
structure with a "next" field.
To avoid this additional layer of allocation and indirection, use a
VecDeque.
The packets queued for recording were wrapped in a dynamically allocated
structure with a "next" field.
To avoid this additional layer of allocation and indirection, use a
VecDeque.
Since in scrcpy a video packet passed to avcodec_send_packet() is always
a complete video frame, it is sufficient to call avcodec_receive_frame()
exactly once.
In practice, it also works for audio packets: the decoder produces
exactly 1 frame for 1 input packet.
In theory, it is an implementation detail though, so
avcodec_receive_frame() should be called in a loop.
By default, scrcpy mirrors only the video when audio capture fails on
the device. Add a flag to force scrcpy to fail if audio is enabled but
does not work.
On Android 11, it is possible to start the capture only when the running
app is in foreground. But scrcpy is not an app, it's a Java application
started from shell.
As a workaround, start an existing Android shell existing activity just
to start the capture, then close it immediately.
Co-authored-by: Romain Vimont <rom@rom1v.com>
Signed-off-by: Romain Vimont <rom@rom1v.com>
Play the decoded audio using SDL.
The audio player frame sink receives the audio frames, resample them
and write them to a byte buffer (introduced by this commit).
On SDL audio callback (from an internal SDL thread), copy samples from
this byte buffer to the SDL audio buffer.
The byte buffer is protected by the SDL_AudioDeviceLock(), but it has
been designed so that the producer and the consumer may write and read
in parallel, provided that they don't access the same slices of the
ring-buffer buffer.
Co-authored-by: Simon Chan <1330321+yume-chan@users.noreply.github.com>
If there is exactly one producer, then it can assume that the remaining
space in the buffer will only increase until it write something.
This assumption may allow the producer to write to the buffer (up to a
known safe size) without any synchronization mechanism, thus allowing
to read and write different parts of the buffer in parallel.
The producer can then commit the write with lock held, and update its
knowledge of the safe empty remaining space.
When audio capture fails on the device, scrcpy continue mirroring the
video stream. This allows to enable audio by default only when
supported.
However, if an audio configuration occurs (for example the user
explicitly selected an unknown audio encoder), this must be treated as
an error and scrcpy must exit.
If no bit-rate is passed, let the server use the default value (8Mbps).
This avoids to define a default value on both sides, and to pass the
default bit-rate as an argument when starting the server.
The permission "android.permission.RECORD_AUDIO" has been added for
shell in Android 11.
Moreover, on lower versions, it may make the server segfault on the
device (happened on a Nexus 5 with Android 6.0.1).
Refs <4feeee8891%5E%21/>