-
-
Notifications
You must be signed in to change notification settings - Fork 10.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add v4l2loopback support #2268
Add v4l2loopback support #2268
Conversation
The recorder thread wrote the whole content except the trailer, which was odd.
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 ebccb9f. 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".
The new API has been introduced in 2016 in libavcodec 57.xx, it's very old. This will avoid to maintain two code paths for decoding.
The new API has been introduced in 2016 in libavformat 57.xx, it's very old. This will avoid to maintain two code paths for codec parameters.
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 will allow to get the parent of an embedded struct.
This trait will allow to abstract the concrete sink types from the packet producer (stream.c).
This will make further commits more readable.
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.
Make recorder implement the packet sink trait. This will allow the stream to push packets without depending on the concrete sink type.
This will make further commits more readable.
Make decoder implement the packet sink trait. This will allow the stream to push packets without depending on the concrete sink type.
Now that decoder and recorder implement the packet sink trait, make stream push packets to the sinks without depending on the concrete sink types.
This trait will allow to abstract the concrete sink types from the frame producer (decoder.c).
Make screen implement the frame sink trait. This will allow the decoder to push frames without depending on the concrete sink type.
Now that screen implements the packet sink trait, make decoder push packets to the sinks without depending on the concrete sink types.
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.
Now that screen is both the owner and the listener of the video buffer, execute the code directly without callbacks.
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 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.
Only initialize ops and parameters copy from recorder_init(). It was inconsistent to initialize some fields from _init() and some others from _open().
There are many initializations in recorder_open(). Handle RAII-like deinitialization using gotos.
EAGAIN was only handled on receive_frame. In practice, it should not be necessary, since one packet always contains one frame. But just in case.
Add a function to know if a string list, using some separator, contains a specific string.
The AVOutputFormat name is a string list: it contains names (possibly only one) separated by '.'
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.
If the option is set without argument, lock the initial device orientation (as if the value "initial" was passed).
Also OBS virtual cam can also be used as source in OBS Studio, so I thought that it can also be used like v4l2 |
Or also using pyvirtualcamera? |
Hi guys , when i use this command : |
Your scrcpy version is too old. |
Sorry , i have a snap package installed and also via apt , it was messing both. |
This feature has been introduced in scrcpy v1.18. You can build/install the latest version very easily: https://github.com/Genymobile/scrcpy/blob/master/BUILD.md#simple |
now i getting this scrcpy 1.21 https://github.com/Genymobile/scrcpy |
How did you create the v4l2 loopback device? |
Yes , i did v4l2-ctl -d /dev/video0 -l User Controls
➜ ~ v4l2-ctl --list-devices |
Might be a permission problem. What are the results of:
|
Is on root user and video group |
Hi @rom1v, I also faced this issue, is there any workaround to fix this? |
try running scrcpy with root |
No, you should not run scrcpy as root. Check with |
@rom1v
|
So your user is not in the
then reboot |
Thanks, the video group added but I got another error now:
|
Looks like the very same error. Did you reboot after adding the video group? |
@rom1v yes I did and this is the new id:
and
|
No:
and
|
Try to output a file to v4l2:
and play it:
|
You definitely have permissions issues with your v4l2 device. |
The previous message:
Worked as expected.
How can I fix this? |
@rom1v Sorry I found the problem. It was because I was using snap version and it needed to get access to the camera by running this command: |
For those experiencing an issue where it "fails to encode", you can try lowering the horizontal resolution by adding: |
Is there something similar for Windows? I mean a way to grab the video from ScrCpy without showing the ScrCpy window? |
@Uzver123 No |
Could you make something like webcam splitter to create virtual webcam, i am interested to using ScrCpy to capture phone's camera and output as webcam, any video capture program can connect to webcam. |
This is a follow up for v4l2loopback support (#2232 #2233) implemented by @martinellimarco.
I refactored scrcpy to support this feature properly, then I rebased @martinellimarco's work to use the refactored codebase.
The main purpose is to make the v4l2 component consume frames directly from the decoder, in order to avoid decoding the video stream twice if mirroring display is enabled:
Here is a summary of the changes:
--render-expired-frames
option (see 8bae1f6 for details)sc_packet_sink
: a component which receives packets. It is implemented by thedecoder
and therecorder
, and thestream
now push its packets to the registered packet sinks (without depending on the concrete sink types)sc_frame_sink
: a component which receives frames. It is implemented by thescreen
(and nowv4l2
), and thedecoder
now pushes its frames to the registered frame sinks (without depending on the concrete sink types)--lock-video-orientation
:initial
. This locks the video in the orientation the device happens to be on start and avoids to pass an explicit value. This mode is set by default when v4l2 sink is enabled.sc_frame_sink
, and be registered to thedecoder
.video_buffer
to always send the very last frame, like for the display (it may skip frames, it's on purpose, is it a problem?)Here is a usage summary:
The video stream could also be captured from OBS.
Thank you for your reviews/feedbacks.