Jump to content

Screen Capture causing CPU Spikes


Recommended Posts

While using the screen capture feature of AutoIT I am having problems with CPU spiking each time it runs.

I created sample code below.

I am creating several tools that use screen capture from the mouse pointer position and in one of the applications I am using two separate screen captures of the same area one would overlay over the other for a zoom effect for example.

The below code uses two screen captures which run in a tight loop for the live effect. I am not saving any files to a drive because it is not needed in the use case I am doing this in.

I read somewhere else with examples in the forum of using "double buffering" but I do not understand this or how to use it in the code below. Not sure if it would work or be useful in this example.  I have seen and have freeware color pickers that use screen capture, maybe done differently and they do not spike the CPU at all.  Why is this code example doing it?

Changing the sleep time in the loop doesn't stop the CPU spikes just happens less frequent though it does happen every time the capture() function runs.

Is there another way to do the below that I can understand?   Took me awhile to figure out how to do this code.

Press 'ESC' to close the application

Thanks for any help.

 

#AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w- 4 -w 5 -w 6 -w- 7
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <ScreenCapture.au3>
#include <GDIPlus.au3>

HotKeySet("{ESC}","close")

Global $gui = GUICreate('Test', 350, 200, -1, -1, $WS_BORDER + $WS_POPUP)
GUISetState(@SW_SHOW)


Func capture()
        Local $getMPos = MouseGetPos()

    _GDIPlus_Startup()

        Local $hScrn1 = _ScreenCapture_Capture("", $getMPos[0] - 10, $getMPos[1] - 10, $getMPos[0] + 10, $getMPos[1] + 10, False)
        Local $hScrn2 = _ScreenCapture_Capture("", $getMPos[0] - 80, $getMPos[1] - 80, $getMPos[0] + 80, $getMPos[1] + 80, False)

        Local $cap1 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn1)
        Local $cap2 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn2)
        _WinAPI_DeleteObject($hScrn1)
        _WinAPI_DeleteObject($hScrn2)


        Local $gObj = _GDIPlus_GraphicsCreateFromHWND($gui)

        _GDIPlus_GraphicsDrawImage($gObj, $cap1, 10, 20)
        _GDIPlus_GraphicsDrawImage($gObj, $cap2, 180, 20)

        _GDIPlus_GraphicsDispose($gObj)
        _GDIPlus_BitmapDispose($cap1)
        _GDIPlus_BitmapDispose($cap2)

    _GDIPlus_Shutdown()
EndFunc

While 1
    capture()
    Sleep(50)
WEnd

Func close()
    GUIDelete($gui)
    Exit
EndFunc

 

Edited by iAmNewbe
Adjusted Code to use separate off sets
Link to comment
Share on other sites

Hmm,

in your exampe, you can skip one screen capture, as it is using the same data which is under the mouse.

Local $hScrn1 = _ScreenCapture_Capture("", $getMPos[0] - 80, $getMPos[1] - 80, $getMPos[0] + 80, $getMPos[1] + 80, False)
        ;Local $hScrn2 = _ScreenCapture_Capture("", $getMPos[0] - 80, $getMPos[1] - 80, $getMPos[0] + 80, $getMPos[1] + 80, False)

        Local $cap1 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn1)
        Local $cap2 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn1)  ;<---- hScrn1
        _WinAPI_DeleteObject($hScrn1)
        ;_WinAPI_DeleteObject($hScrn2)

Unless you want to offset the hScrn2 to something else, i would do it in this way.

About double buffering: It is used to make drawing on the screen smooth and to avoid  flickerings.

You (basically) have 2 drawing buffers, which are displayed one after other. While the one is being shown, the other receives the drawing operations.

At the loop end, the buffers are switched, so that the buffer, which received the drawing, shows its contents, and the other buffer becomes the receiver.

It is, technically a 

flipbook animation technique, just that the computer uses only 2 papers for drawing, because it can switch and draw on them on the fly.

Edited by Dan_555

Some of my script sourcecode

Link to comment
Share on other sites

Yes in my actual code I have different offsets for the two screen captures. I adjusted the code in the OP to reflect this instead of just saying that i did this in the explanation.

How do you implement the buffering?

The CPU still spikes whether it is one or two screen captures.  Why and how to fix this?

Link to comment
Share on other sites

Local $hScrn1 = _ScreenCapture_Capture("", $getMPos[0] - 80, $getMPos[1] - 80, $getMPos[0] + 80, $getMPos[1] + 80, False)
        
        Local $cap1 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn1)
        
        _GDIPlus_GraphicsDrawImage($gObj, $cap1, 180, 20)
        _GDIPlus_GraphicsDrawImage($gObj, $cap1, 180, 20)

In this example...  Is this double buffering?     

You said one gets drawn to then the other received the finished drawing. But the above is just drawing over the other simultaneously.   I thought that the "Buffer" was stored in memory and used like a temporary cache.  I am not understanding this yet.

Edited by iAmNewbe
corrected typos
Link to comment
Share on other sites

You can look at some examples in here: 

 

Double buffering is used mainly for games.

A screenshot is a kind of buffer, but it doesn't need double buffering, because you are not modifying it on the fly.
 

Edited by Dan_555

Some of my script sourcecode

Link to comment
Share on other sites

Here the spike is almost not noticeable.

Well, at the Start, the fan could be heard (i guess ~20% of rotation speed), but then, after about 5~10 seconds it becomes silent again (~10%). 

I'm not an expert in GDI(+) but i guess it can be done like this too: 

#AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w- 4 -w 5 -w 6 -w- 7
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <ScreenCapture.au3>
#include <GDIPlus.au3>

HotKeySet("{ESC}","close")

Global $gui = GUICreate('Test', 350, 200, -1, -1, $WS_BORDER + $WS_POPUP)
GUISetState(@SW_SHOW)
 Global $gObj

Func capture()
        Local $getMPos = MouseGetPos()

        Local $hScrn1 = _ScreenCapture_Capture("", $getMPos[0] - 80, $getMPos[1] - 80, $getMPos[0] + 80, $getMPos[1] + 80, False)
        Local $hScrn2 = _ScreenCapture_Capture("", $getMPos[0] - 180, $getMPos[1] - 180, $getMPos[0] + 180, $getMPos[1] + 180, False)

        Local $cap1 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn1)
        Local $cap2 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn2)  ;<---- hScrn1
        _WinAPI_DeleteObject($hScrn1)
        _WinAPI_DeleteObject($hScrn2)

        _GDIPlus_GraphicsDrawImage($gObj, $cap1, 10, 20)
        _GDIPlus_GraphicsDrawImage($gObj, $cap2, 180, 20)

        _GDIPlus_BitmapDispose($cap1)
        _GDIPlus_BitmapDispose($cap2)

EndFunc

  _GDIPlus_Startup()
  $gObj = _GDIPlus_GraphicsCreateFromHWND($gui)

While 1
    capture()
    ;Sleep(40)
WEnd


Func close()
    _GDIPlus_GraphicsDispose($gObj)
    _GDIPlus_Shutdown()
    GUIDelete($gui)
    Exit
EndFunc
Edited by Dan_555
Placed GDI_Shutdown into the close function !

Some of my script sourcecode

Link to comment
Share on other sites

I opened Task Manager and looked at the Processes tab.  Comparing your version to the original I don't see any change in the CPU column or how often it jumps to 01 for the process.  I compiled it out to EXE and watched that.   Also switching to the Performance Tab you see the increase activity everytime the capture() function runs.

I don't know.  Maybe it is not fixable in this use case?   
I can survive it, where I will be using this won't be active for very long so it won't be a long term stress, just when needing to see what is directly under the cursor.
Like a Color, or for absolute positioning an element say on a web page, or setting points between locations on a screen for comparing distance or whatever.

Thanks for your help.

Edited by iAmNewbe
Link to comment
Share on other sites

I created a Toggle switch to turn on and off the screen capture via the space bar.  Doesn't solve the problem but allows for opting to not run or "pause" the screen capture.

 

Global $toggle = 0
HotKeySet("{SPACE}","toggleScreenCap")

While 1
    If $toggle = 0 Then capture()
    ;Sleep(40)
WEnd

Func toggleScreenCap()
    If $toggle = 1 Then 
        $toggle = 0
    ElseIf $toggle = 0 Then 
        $toggle = 1
    EndIf
EndFunc


 

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...