Hardware Accelleration / Playing Video

I'm trying to display video using Java, but I'm having real problems getting the speed I desire.

I get an array of bytes which represents the uncompressed pixels of the current video frame from some C code using the JNI. This Byte array is part of a DataBufferByte, which is part of a WritableRaster, which is part of a BufferedImage. Loading the bytes this way can be done at a full 30 frames per second (fps) and uses less than half of my CPU. However, when I try to render this BufferedImage to the screen or to a VolitileImage, it takes all of my CPU and I can achieve at best a mere 15 fps.

I think my problem is that the pixels are being loaded into system memory instead of video memory. No matter what priority settings or -D command line options I use, the BufferedImage I create never seems to be hardware accelerated. I've tried both Java 1.5 and 1.6 also, but isAccelerated() always returns false for my BufferedImages made from WritableRasters.

I can create a VolitileImage that is hardware accelerated, but I have no way of accessing the pixel buffer associated with it, in order to load new video frames in. Rendering the BufferedImage into this VolitileImage is almost as slow as rendering it straight to the screen (but not quite, oddly enough). Does anyone have any ideas on how to load raw, uncompressed pixel data into an accelerated image?

Background:

The application I'm working on must play video in a Java window. This application must run on both Linux and Windows (so no using Quicktime for Java) and it must handle multiple videos at once (so I can't use OpenGL in C since OpenGL doesn't support multiple threads at all). I tried using IBM's MPEG for Java but it was far too slow. I lookd at the JMF, but it seems to be old, unsupported and disliked, plus it does not support all the formats I need. The only solution that seems fast enough (and platform independent) is to use the ffmpeg library (which is also used by mplayer and vlc). However, since ffmpeg is a C library, this requires using the JNI.

If there is no way to improve the rendering speed in Java, I may have to write separate rendering algorithms in C using DirectX for Windows and XVideo for Linux. I would like to avoid this if possible. Thanks for any help.

[2304 byte] By [CLaBrundaa] at [2007-10-3 3:03:52]
# 1

Yes, such image indeed will not be accelerated - because you have the pointer to the raw data.

Here is an approach which I've suggested to other people with similar issues.

Create a VolatileImage

Copy your BufferedImage to this volatile image

copy the volatile image to the back-buffer

This approach especially helps if you need to copy the image to the backbuffer more often that it's updated by the video stream, or if you need to scale the frames (in the last case you'll need to use -Dsun.java2d.ddscale=true parameter if you're running on windows, or the opengl pipeline with -Dsun.java2d.opengl=true if your hardware/drivers is supported).

Take a look at this thread on javagaming.org which discusses almost exactly the same case as yours:

http://www.javagaming.org/forums/index.php?topic=12453.msg100335#msg100335

Thank you,

Dmitri

Java2D Team

dmitri_trembovetskia at 2007-7-14 20:53:51 > top of Java-index,Security,Cryptography...
# 2

Thank you very much dmitri, the thread you linked showed me just how to make it work. Now I can get 30fps with two videos at once.

Previously, I was trying to build up a BufferedImage from a 24bit RGB array of pixels, which I don't think is compatible with most hardware acceleration. Now I get a pointer to a 32bit RGBA array, using:

BufferedImage videoImage;

GraphicsConfiguration gc = videoCanvas.getGraphicsConfiguration();

videoImage = gc.createCompatibleImage(vidWidth, vidHeight);

pixelData = ((DataBufferInt) videoImage.getRaster().getDataBuffer()).getData();

With minor changes to my C code I store the pixels in this buffer instead. This works much better, as the resulting BufferedImage is hardware accelerated. I then can render this BufferedImage straight to the screen, with scaling, very quickly.

Rendering it first to a VolitileImage was causing problems for me, as performance would slow down for some reason if I changed the window's size at all while it was running.

CLaBrundaa at 2007-7-14 20:53:51 > top of Java-index,Security,Cryptography...
# 3

Glad it helped.

Be careful with using createComatibleImage: the format of the returned image depends on the desktop depth. So if you change your display mode to 16-bit, your code will break.

Instead you can use

videoImage = new BufferedImage(vidWidth, vidHeight, BufferedImage.TYPE_INT_RGB);

Thanks,

Dmitri

dmitri_trembovetskia at 2007-7-14 20:53:51 > top of Java-index,Security,Cryptography...