Graphics::drawImage consumes a lot of CPU


#1

I am building a video player using Juce. I call repaint() 30 times per second on my component. My paint() method looks like :

if (! m_pCurrentFrameImage.isNull())
g.drawImage(&*m_pCurrentFrameImage,
0,
0,
getWidth(),
getHeight(),
0,
0,
m_pCurrentFrameImage->getWidth(),
m_pCurrentFrameImage->getHeight());

If I comment out the above call to drawImage(), CPU consumption is approx. 5%, most of which is probably spent decoding video frames. However, when I uncomment the call to drawImage(), CPU consumption jumps to 45% for a 500 by 700 pixel image on a recent (i5) processor (Windows 7). When I play the same video in Windows Media Player, CPU consumption is less than 10%.

Is there a more clever way to display the video frames to minimize CPU consumption ?


#2

Windows Media hooks into any available hardware resources to perform video decoding and display. You will never reach the speed of Windows Media player unless you do the same. This goes outside the scope of the Juce library.


#3

yeah, unfortunately, shifting that amount of memory around 30 times a second is going to burn CPU. The only way you could do better would be like Vinn says, to use some kind of OS hardware pipeline to do it.


#4

Thanks for the replies, Jules and Vinn.

In my Juce application, I replaced the call to repaint() by a call to OpenCV’s cvShowImage() function. This function displays a bitmap in a separate window which is not very functional but is interesting for comparison purposes. Using cvShowImage(), CPU usage goes down to roughly the same as Windows Media Player. It looks like hardware acceleration is not what explains dramatically lower CPU usage because OpenCV’s cvShowImage() is implemented using ::CreateDIBSection().

I will dig deaper to try to understand why Juce consumes more CPU than OpenCV to display an image but do you have a clue why this is so ?

I figure that other people wanting to use Juce to write a video player will run into the same kind of problems on Windows.


#5

If this is the case, then write a small test program that first draws a juce Image 1000 times and then draws the same image using a DibSection 1000 times and times the result. Make sure your test app fits into a single .cpp file, only uses Juce (you may need to copy/paste some cv source code or write your own CreateDibSection / BitBlt skeleton). Post the test app using ‘[code]’ BBCode.

And post your test app in the forum so we can have a look-see.


#6

If the goal is the best possible performance, Juce will never live up to it because top end video players always use the platform-specific video codecs that have hardware acceleration, and that is beyond the scope of Juce.


#7

No, the goal is not best performance, the goal is just to be able to play back a single video and audio channel on a machine that is 3-4 years old without hogging 100% of the CPU.

I will write the sample you suggested.


#8

Great! If there is something that can be improved, I am 100% confident that I will find it with VTune Analyzer.


#9

Upon further investigation, I discovered the cause of the excessive CPU consumption in my video player : rescaling the image to fit it in the component. drawImage() does that automatically for you. But if I instead call drawImageAt() and make sure to clip the image if required, no rescaling takes place and CPU consumption falls from 45% to 15% in my Juce application.

When you launch Windows Media Player, it automatically resizes the window to the video frame size to avoid rescaling. I will implement the same functionality in my juce player.

I am currently running a debug build, it will be interesting to see by how much CPU consumption decreases in the release build. In the end, the juce player CPU consumption could be very close to Windows Media Player.


#10

LOL and LOL

[attachment=0]facepalm.jpg[/attachment]