sskodje / ScreenRecorderLib

A .NET library for screen recording in Windows, using native Microsoft Media Foundation for realtime encoding to h264 video or PNG images.
MIT License
414 stars 94 forks source link

Low FPS and border flicker when TestApp is not on the monitor you are recording #324

Open rwedoff opened 1 week ago

rwedoff commented 1 week ago

Hi I have noticed for a few versions (checked all the way back to v6.0.0) that when the TestApp window is not on the monitor that I am actively recording, the FPS is significantly lower, almost half, and the border (Windows Graphic Capture), is flickering, almost like an exception or something is being thrown.

Repro Steps:

Is there something that is throwing an exception or needs to be fixed?

sskodje commented 5 days ago

That's odd behavior. I tried to reproduce your steps, but I did not experience this issue. Are there any errors in your logs?

rwedoff commented 4 days ago

I am seeing a few errors with InitializeVideoSink and then a bunch of "Restarted Windows Graphics Capture"

For this log, I placed the TestApp on my primary monitor (which does seem to matter in this case), and recorded my secondary monitor

2024-11-11 09:11:58.550 [ERROR] [OutputManager.cpp | InitializeVideoSink: 454] >> BAD HR: hr=0x80004002, error is: No such interface supported 2024-11-11 09:11:58.630 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:11:58.683 [DEBUG] [OutputManager.cpp | BeginRecording: 103] >> Sink Writer initialized 2024-11-11 09:11:58.689 [DEBUG] [RecordingManager.cpp | StartRecorderLoop: 736] >> Changed Recording Status to Recording 2024-11-11 09:11:59.198 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:11:59.739 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:00.315 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:00.890 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:01.443 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:02.004 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:02.590 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:03.145 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:03.708 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:04.280 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:04.849 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:05.407 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:05.963 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:06.512 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:07.087 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:07.638 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:08.193 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:08.767 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:12:09.341 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture

BadLog.txt

rwedoff commented 4 days ago

Actually another data point, if I chose both monitors (both Windows Graphics Capture), whichever monitor didn't have the TestApp on, had a flickering border. AllMonitors.txt

sskodje commented 4 days ago

Hmm yeah, the restart loop is definitely the cause of the flickering and low framerate. I can see what is happening, WGC stops producing frames, and is restarted. The question is why this happens. Just to test a hunch, if you place a youtube video or something on each of the monitors, does it change anything?

rwedoff commented 4 days ago

Roughly the same behavior, maybe a little less flickering, but that could be just slow performance with lots of stuff running at once.

sskodje commented 4 days ago

I can't understand why it should matter on what monitor the app is. I thought initially that perhaps it did not produce any new frames because nothing happened on the monitor without the app on. This is very strange. I can't reproduce it at all, so it must be some difference between the computers.

rwedoff commented 4 days ago

I have asked a few other people, with other laptops/desktops and they were able to repro.

sskodje commented 3 days ago

I tried on my laptops and desktops with windows 10 and windows 11 but unfortunately i still can't reproduce. Could you comment out these lines and see what happens?

rwedoff commented 3 days ago

Commenting out those lines does indeed fix it! High FPS and no flicker then!

sskodje commented 3 days ago

Alright, we found the problem, but what is the cause? That code should not have triggered unless the Windows Graphics Capture api stops sending frames for a length of time. Perhaps the timeout is too short for some scenarios? If you comment back in those lines, and then change the value on this line from 250 to say 1000 or 2000, does the problem come back?

rwedoff commented 3 days ago

Problem comes back, but rather flickers about every second/1000ms in this case. Similar logs as before. 2024-11-11 09:24:28.006 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:24:28.006 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:24:28.111 [DEBUG] [OutputManager.cpp | BeginRecording: 103] >> Sink Writer initialized 2024-11-11 09:24:28.118 [DEBUG] [RecordingManager.cpp | StartRecorderLoop: 736] >> Changed Recording Status to Recording 2024-11-11 09:24:28.568 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:24:29.290 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:24:29.849 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture 2024-11-11 09:24:30.417 [INFO] [WindowsGraphicsCapture.c | ProcessRecordingTim: 451] >> Restarted Windows Graphics Capture

rwedoff commented 3 days ago

Was randomly poking around and removed the RETURN_ON_BAD_HR, but kept the start and stop. The issues goes away then. image

sskodje commented 2 days ago

Interesting find. What is the logged error message on the bad HRESULT?

rwedoff commented 2 days ago

My apologies there, I still had the increased time out. After debugging the HR is Ok after all for the stops and starts. Back to square one on why the frames are coming in late.

rwedoff commented 2 days ago

Going back to your "Youtube" theory. I have noticed something while trying to debug this more. If I move the mouse a bunch around the screen that it is recording, the framerate goes up to the expected values. I also have tested this with Desktop Duplication on the display and I get the same issue (low FPS, there is no border shown, so no flicker).

It could be that, "the test app is on the recording screen fixes this" because there is a timer that is adding motion to the screen, which would be the same as the YouTube video or the mouse movement. The Youtube video itself, cause some perf issues on my machine since I am using a VM, which is why that didn't pan out at first.

sskodje commented 1 day ago

Yes that's my leading theory as well. Perhaps it's a quirk with virtual machines, that they stop delivering frames if there is no movement, since this can't be reproduced on my physical hardware. I believe i can circumvent the problem by removing the timeout check when recording monitors, as the issue was initially that some window recordings had to be restarted when doing things like maximizing them.

rwedoff commented 1 day ago

Tried out on a physical machine and had the same issue. I really can't think why OnFrameArrived isn't being fired in time for these cases, causing the delay. If removing the timeout check for monitors works, that would probably suffice then.