Hi,
EDIT: TL;DR:
I’m using ffmpeg to decode video, so I get all the benefits of hardware acceleration that it provides.
I get decoded RGB frame data from ffmpeg from each frame and put it into a Raster bound to a BufferedImage.
I render the BufferedImage. This bit is slow.
I’m implementing a Java-based media player that’s hooked into the ffmpeg media library. I’m simultaneously decoding multiple video streams and displaying them in a number of lightweight java components across 4 monitors. However, I’m encountering performance issues when rendering the decoded video to screen. The video decoding part is negligible here (approx. 10% CPU use on 1 core) so I’m not going to discuss that here. The issue arises in the swing painting code, which blocks deep within Java’s Direct2D code while scaling/drawing the image itself, so I hope someone might be able to help me here.
I currently receive the image as a series of ints in packed 0rgb format (this is flexible, so I can use whatever colour model and packing gives best performance). The data is written directly into an image raster that I’ve instantiated in the following manner:
imageBuffer = new DataBufferInt(lineStride * height);
imageRaster = Raster.createPackedRaster(imageBuffer, width, height, lineStride, new int[] {0xff0000, 0xff00, 0xff}, null);
ColorModel colourModel = new DirectColorModel(32, 0xff0000, 0xff00, 0xff);
currentFrame = new BufferedImage(colourModel, imageRaster, true, null);
currentFrame.setAccelerationPriority(1.0f);
This code is only called once per video player and the raster and bufferedImage re-used for each subsequent frame.
Each time a new frame is decoded, the data is copied into the raster and repaint(30) called (to trigger an asynchronous swing repaint).
I am currently hitting 100% CPU usage on a Core i5 with the following scenario:
Four 1280x1024 monitors are connected to the PC.
Four 720x576 videos are being decoded at 25FPS (this is handled by ffmpeg and is not the contributing factor to the performance issues)
Each monitor is displaying a single JFrame without window decordations, scaled to fit the entire monitor
The JFrame’s paintComponent method is overridden with the paint code as follows:
graphics.setColor(Color.BLACK);
graphics.fillRect(0, 0, getWidth(), getHeight());
graphics.drawImage(currentFrame,
0, 0, getWidth(), getHeight(),
0, 0, currentFrame.getWidth(), currentFrame.getHeight(),
null);
For comparison, if I use four full-screen media players (such as VLC or ffplay), each playing one of the streams, the total CPU usage is around 30%.
I have experimented with various options (such as disabling Direct3D, etc) but without any real gains and mostly losses/unexpected behaviour. I have also considered using full-screen exclusive mode but would like to know whether this is likely to help before I try that route.
Does anyone have any suggestions? I’m happy to elaborate on any areas of the code that may be relevant.