-
-
Notifications
You must be signed in to change notification settings - Fork 10.7k
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
Record screen to file #292
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI, I have some advice about insignificant little problems.
@@ -207,14 +211,15 @@ static SDL_bool parse_args(struct args *args, int argc, char *argv[]) { | |||
{"fullscreen", no_argument, NULL, 'f'}, | |||
{"help", no_argument, NULL, 'h'}, | |||
{"max-size", required_argument, NULL, 'm'}, | |||
{"output", required_argument, NULL, 'o'}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion, the output
is too general. In the future, we may add some feature like output format. It make a bit confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--output-file?
@@ -235,6 +240,9 @@ static SDL_bool parse_args(struct args *args, int argc, char *argv[]) { | |||
return SDL_FALSE; | |||
} | |||
break; | |||
case 'o': | |||
args->outfilename = optarg; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make consistent, use underscore as delimiter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
@@ -228,7 +228,7 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { | |||
} | |||
|
|||
ret = event_loop(); | |||
LOGD("quit..."); | |||
LOGI("quit..."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion, LOGD
is good enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your contribution.
I compiled it (after changing CODEC_FLAG_GLOBAL_HEADER
, which does not exist in my FFmpeg, to AV_CODEC_FLAG_GLOBAL_HEADER
) and run it with scrcpy -o test.h264
.
A video file is correctly recorded, and can be played with VLC or MPV. That's great an interesting 👍
However, the framerate of the video stream received from the device is (very) variable, and is not respected in the resulting video file. For example, if I navigate to a screen which is "constant" (no pixel is changed) and stay on this screen for 10 seconds, then navigate to another application, in the resulting video file, the 10 seconds are not preserved (it immediately switches to the other application).
This is confirmed by the warning given by mpv
:
[lavf] This format is marked by FFmpeg as having no timestamps!
[lavf] FFmpeg will likely make up its own broken timestamps. For
[lavf] video streams you can correct this with:
[lavf] --no-correct-pts --fps=VALUE
[lavf] with VALUE being the real framerate of the stream. You can
[lavf] expect seeking and buffering estimation to be generally
[lavf] broken as well.
(and by the seekbar behavior both in VLC and mpv)
So to preserve timestamps, the H.264 raw stream should be muxed into a container like mkv or mp4 I guess.
Writing to a file is blocking, so ideally, it should be done in a thread separated from the decoder thread (otherwise it can block/slow down decoding, resulting in frame drop). It does not matter as much as if it were the UI thread though.
As a side note, recording on the client side will include the jitter from communication from the server to the client (see #21 (comment)). Maybe it would be "better" to mux on the server side (only when recording is enabled to avoid additional latency when nothing is recorded). What do you think?
Also, what could we do on device rotation?
Thank you! I am adding muxing to the server, but it only supports Android 8.0+ because MediaMuxer(FileDescriptor fd, int format) is not available in earlier versions. While MPV correctly handles frame size changes in the same video file, creating a new file on rotation may be a better option. |
In addition, it says that the "File descriptor must be seekable", which is not the case. It seems it cannot mux into a container that can be streamed in live. Recording on the client side is still acceptable to me, it just makes me sad that people will use it for recording video of games or whatever, while But this would still be a great feature to be able to record to mkv locally.
Frame size changes in the same video file will probably cause problems (mkv only defines the video size once; however VLC should still handle frame size change properly in theory).
Yes, but it would require a pattern to generate new files (instead of just a filename). Why do you think about just storing the video rotated? For example, if we start recording in 1200x720, then rotate to 720x1200, the video would be recorded "rotated" in 1200x720? The first frame would define the dimensions. (This is not that simple though, in theory, the frame size may change to arbitrary dimensions) |
In my latest experiment, the server sends headers with packet size and PTS before encoded packets: I like the idea about recording rotated video to keep constant frame size, but is it possible without re-encoding? |
(just acking your message, I'll try to review it next week, thank you) |
@igorinov I just tested your It records a file, but unfortunately, the timestamps are still not respected in the resulting file (like #292 (review)). IMO we need to mux in a container like mp4 or mkv. |
Ah, that's because I saved to (Is it possible to specify the target container explicitly?) |
I think it should be recognized by extension, if CONFIG_MATROSKA_MUXER is enabled in the build configuration: AVOutputFormat ff_matroska_muxer = { |
I tried recording to .mkv on a Linux machine, and the file was played successfully with cvlc. |
Arf, on Debian sid, I cannot record to mkv :( I like your branch, and it would be great to get recording into scrcpy. But there are still some issues to solve. If I record to mp4, the resulting mp4 file takes a very long time to load in vlc, so it is not "proper" (while a file recorded by If I take your current branch, (after I changed
I have no time to investigate on this currently. I'll try to find some time later. If you have some time and find how to fix these issues, that would be awesome 😉 Thank you. |
I just found the problem: the PTS given by There are still little problems, for example on quit:
|
For me, it fails at |
@igorinov I had some time today to work on it. I started from your commit, and did these changes:
Here is my branch:
It correctly records rotation, and plays correctly in VLC 😄 Remaining things I will work on:
|
Oh, all PTS are not assigned to the right frame, we immediately use the last PTS read for the current decoded frame. EDIT: fixed by 0cb16be |
Hi, @rom1v I cloned the branch record and tried to build.
Thanks, |
@npes87184 Thank you for your test.
Yes, that's the reason I planned to:
😉 |
Hi, @rom1v Thank you for your explanation. At the first glance, it works like a charm! Thanks, |
Ah yes, this need to be fixed too. Thank you. Basically, reverting f00c6c5 works, but we need to fix what this commit prevented. |
Or set a flag to call |
I think we have a version ready to be merged: branch I also changed the option name:
If you want to test before the merge/release, feedbacks are welcome :) |
This change enables writing AV packets received from the target to a video file without re-encoding.