BoboTiG / python-mss

An ultra fast cross-platform multiple screenshots module in pure Python using ctypes.
https://pypi.org/project/mss/
MIT License
1.01k stars 93 forks source link

gdi32.GetDIBits() and .grab() usage limitations. #122

Closed roninpawn closed 5 years ago

roninpawn commented 5 years ago

General information:

Description of the warning/error

gdi32.GetDIBits() failed.

I've been through some issue reports here on github regarding gdi32.GetDIBits() failed, and I've resolved the error it was causing in my code. But I wanted to share the pieces I think I've put together on the when and why of this arising. (while using the .grab() method)

In one issue report (https://github.com/BoboTiG/python-mss/issues/59) I picked up that it would be more optimal if I didn't instantiate "with mss.mss() as sct:" on every screenshot I pulled. So I basically nested my whole script in this declaration. Then I started getting this "gdi32.GetDIBits() failed" error after a few minutes of unfettered operation.

My script is watching the screen constantly, so its racking up about 60 screenshots per second. One of the previous issues tallied the number of screenshots required to make HIS code fail with this error at OVER 9000!!! 9,996 precisely. I think his name was Vegeta.

Another issue (https://github.com/BoboTiG/python-mss/issues/83) was resolved by recommending the user switch to taking pure .shot()'s instead of .grab()'s, because, as 'BoboTiG' put it:

mss().grab(...) is not ideal as it will not close opened resources and so, after N calls it will fail.

With this information in hand, I resolved the issue in MY code by simply going back to instantiating "with mss.mss() as sct:" on every screenshot called.

I'm reporting this issue without submitting code because it seems to be a known thing, but maybe the pieces haven't been assembled yet. Or maybe it's just gotten pushed into the "bother me later" pile.

From an outside perspective it seems like the .grab() method needs some garbage collection process so it doesn't overload it's own resources on repetitive use. Now, I could integrate that myself with a counter to tally up how many .grabs() I've done, and after N'th .grabs, call "with mss.mss() as sct:" again to clear the backup -- and I may do just that.

But that seems like something that ought to be resolved within the library so as not to complicate implementation and usage.

Thanks for the twice-as-fast-as-numpy's screenshot library! This project was dying under low-frame counts until I found mss. Hopefully this helps, if not development, the next person who comes along going, "What does gdi32.GetDIBits() failed mean?"

BoboTiG commented 5 years ago

Hello @roninpawn,

Thanks for raising that issue. I rechecked the code and I may be able to make grab() safe on Windows. But now that I recall, this will impact MSS performances. I will give a try and write some results in this thread. We will then decide if it is worth doing the changes for everyone :)

BoboTiG commented 5 years ago

Could do have a try with the version from the fix-resource-leaks branch? It should be way better.

roninpawn commented 5 years ago

Hey, thanks a lot! I'm deep in the project MSS is helping me out with now and I honestly doubt I'll get around to trying the branch in the immediate future. Sorry. Hope reporting helps development. But when I've got a finished-ish build up, I'll see about coming back to give it a go.

I'm pegged at about 60fps right now with my implementation, which is a-okay for the task. But more frames is better and if I take another pass at optimization, that'll be the thing that gets me into the branch.

Thanks again for your work.

BoboTiG commented 5 years ago

I merged the PR, so no more leaks and any sort of MSS calls are OK now :)