views:

58

answers:

2

Hi,

in my project I've got a class FrameProducer firing events each time a video frame has been created. Each frame is an image returned as an java.awt.Image.BufferedImage object.

I've got 2 FrameProducer objects and would like to render BufferedImage's produced by them simultaneously on the screen. I would like the picture rendered on the screen to be scalable (ie. when I drag the application-window's corner the rendered video gets smaller or bigger).

How do you think is this best do be achieved?

I've considered using java.awt.Graphics2D embedded in an java.awt.Frame, but don't know how such a thing can be done or if this is the best choice. I just need this for algorithm visualisation, it doesn't need to be nice and shiny, just fast and easy. Has maybe anyone got some ready code I could use or suggestions?


Edit: Ok, I implemented the solution as Rekin suggested, and it works. But as I'm not an Java expert and definately not a Swing expert, I'd like to ask you for kind remarks on my code - I'm sure many will benefit from that in the future.

As I said, there is a FrameProducer (never mind the implementation):

public abstract class FrameProducer extends Observable {
    public abstract BufferedImage getFrame();

    public void fireEvent() {
        setChanged();
        notifyObservers();
    }
}

Then there is also a FrameRenderer waiting for events from the FrameProducer (a simple observer-pattern implementation using java.util):

public class FrameRenderer extends JPanel implements Observer {
    private BufferedImage frame;
    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.drawImage(frame, null, 0, 0);
        g2d.dispose();
    }
    @Override
    public void update(Observable observable, Object arg) {
        System.out.println("Cought an event from " + observable.getClass());
        if (observable instanceof FrameProducer) {
            frame = ((FrameProducer) observable).getFrame();
            paint(getGraphics());
        }
    }
}

And then there is also the thing that needs rework: the MainFrame.

public class MainFrame extends JFrame {

    FrameProducer[] producers;

    public MainFrame(FrameProducer[] producers) {
        this.setTitle("Playing what you feed.");
        this.producers = producers;
        initContents();
        setVisible(true);
    }

    private void initContents() {
        FrameRenderer renderer = new FrameRenderer();
        renderer.setLocation(0, 0);
        this.add(renderer);
        producers[0].addObserver(renderer);
    }
}

It all gets initialised in the main method:

public class FrameAccessTest {
    public static void main(String[] args) {
        final FrameProducer frameGrabber = new CameraFrameGrabber("vfw://0");

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    MainFrame mainFrame = 
                        new MainFrame(new FrameProducer[] {frameGrabber});
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

How do I implement initContents() in such a way, that all the video streams provided in MainFrame's constructor as FrameProducer[] get rendered in a row and that they are scalable?

Again, thanks for any help.

+2  A: 

I'd go with JPanel and overriding paintComponent method. In it I'd use Graphics2D.drawImage() giving width and height of container as a parameters to it.

The AWT approach seems closer to bare metal, but since JDK 6 brought a lot of improvements in Swing rendering pipeline, I would go the Swing & Java2D approach. It's accelerated by available hardware (using DirectDraw on Windows or OpenGL wherever possible) and hides a lot of low level details behind a nice API. For example You get double buffering for free.

Rekin
Thank you for your answers. I'll give it a shot and post my code when done, maybe you'll have any comments.
mmm
Glad to be of any help. I faced similar challenge a number of times. Also got a little OpenGL expertise out of it, so don't hesitate asking.
Rekin
OK, I added my code. Take a look, if you could, please.
mmm
A: 

Override the paintComponent method and use Graphics2D to draw your buffered image using drawImage. This method is overloaded and can be used to scale the image as well.

Faisal Feroz