This discussion is archived
4 Replies Latest reply: Jan 19, 2012 8:56 PM by TadashiOhmura RSS

How to control a webcam in JFX app?

870239 Newbie
Currently Being Moderated
Hi,

Any good ideas to implement image capture with webcam?
I haven't really done anything code like that before so I'm up for good ideas.

I tried to google it and most of the results talked about Java Media Framework which seems pretty old API and not updated lately. Any other options or should I go with that?

- Kasperi
  • 1. Re: How to control a webcam in JFX app?
    jsmith Guru
    Currently Being Moderated
    Webcam supported isn't scheduled until the Lombard release, which is a long way out.

    The Jira request to support cameras is one of the oldest open issues http://javafx-jira.kenai.com/browse/RT-3458 - it also ranks 5th on the list of highest voted issues.

    In the Jira request, Daniel mentions that he did some work on adapting the Java Media Framework webcam support for use in a JavaFX application he created, apparently he wasn't all that happy with the solution.
    If he doesn't reply directly to this post, you could ask him about it at his blog => http://www.zenjava.com/

    Past projects I have worked on have implemented webcam support by JNI calls out to native platform APIs - it was tricky threading-wise and non-portable, so I can't really recommend that approach if you can find something better.
  • 2. Re: How to control a webcam in JFX app?
    875756 Pro
    Currently Being Moderated
    JMF was flaky, it sort of worked sometimes. I ended up ditching it and replacing it with: LTI-CIVIL (http://lti-civil.org/)

    So far it has been very stable and is working well (although it only works in a 32 bit JVM but JMF is the same and I didn't find any 64bit toolkits anywhere).

    Obviously it's all Swing-based (nothing exists for JFX yet) but using the JFX Swing embedding stuff it should work ok. I went with a popup JFrame for my purposes (since I'm taking a photo and it was just for a demo/pitch). The popup shows the live stream from the video camera, i.e. a 'webcam'.

    LTI-CIVIL just grabs images from the camera (at a given framerate) and then passes them to your code via callback. You can do whatever you want with the images but LTI-CIVIL has a pane in it that draws the images in sequence to create the 'movie' (I thought this approach would be slow but it seems to work fine).

    The following is my code - as I said, it was demo code so its not polished/production-grade but it works:
    import com.lti.civil.*;
    import com.lti.civil.awt.AWTImageConverter;
    import com.lti.civil.swing.ImageFrame;
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.image.BufferedImage;
    import java.util.List;
    
    public class PhotoCaptureTool
    {
        public void capturePhoto(PhotoCaptureHandler handler)
        {
            try
            {
                CaptureSystemFactory factory = DefaultCaptureSystemFactorySingleton.instance();
                PhotoCaptureFrame captureFrame = new PhotoCaptureFrame(factory, handler);
                captureFrame.run();
            }
            catch (CaptureException e)
            {
                handler.captureError("Error capturing photo", e);
            }
        }
    
        //-------------------------------------------------------------------------
    
        public class PhotoCaptureFrame extends ImageFrame
        {
            private BufferedImage lastImage;
            private CaptureSystem system;
            private CaptureStream captureStream;
            private final CaptureSystemFactory factory;
            private PhotoCaptureHandler handler;
            private volatile boolean disposing = false;
    
            public PhotoCaptureFrame(CaptureSystemFactory factory, PhotoCaptureHandler handler)
            {
                super("Take Photo");
                this.factory = factory;
                this.handler = handler;
            }
    
            public void run() throws CaptureException
            {
                setDefaultCloseOperation(DISPOSE_ON_CLOSE);
                initCapture();
                setAlwaysOnTop(true);
    
                addWindowListener(new WindowAdapter()
                {
                    public void windowClosing(WindowEvent e)
                    {
                        disposeCapture();
                    }
                });
    
                JPanel buttonBar = new JPanel(new FlowLayout(FlowLayout.CENTER));
    
                JButton takePhotoButton = new JButton("Take Photo");
                takePhotoButton.addActionListener(new ActionListener()
                {
                    public void actionPerformed(ActionEvent e)
                    {
                        handler.photoCaptured(lastImage);
                        disposeCapture();
                        setVisible(false);
                    }
                });
                buttonBar.add(takePhotoButton);
    
                JButton cancelButton = new JButton("Cancel");
                cancelButton.addActionListener(new ActionListener()
                {
                    public void actionPerformed(ActionEvent e)
                    {
                        disposeCapture();
                        setVisible(false);
                    }
                });
                buttonBar.add(cancelButton);
                //getContentPane().add(buttonBar, BorderLayout.SOUTH);
    
                Component[] components = getContentPane().getComponents();
                for (Component component : components)
                {
                    if (component instanceof ImageComponent)
                    {
                        component.setBackground(Color.BLACK);
                        component.addMouseListener(new MouseAdapter()
                        {
                            public void mousePressed(MouseEvent e)
                            {
                                handler.photoCaptured(lastImage);
                                disposeCapture();
                                setVisible(false);
                            }
                        });
                    }
                }
    
    
                VideoFormat format = captureStream.getVideoFormat();
                System.out.println("Capture size: with=" + format.getWidth() + ", height=" + format.getHeight());
    
                JPanel placeHolder = new JPanel(new BorderLayout());
                placeHolder.setOpaque(true);
                placeHolder.setBackground(Color.white);
                placeHolder.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                JLabel label = new JLabel("Please wait, starting camera ...");
                label.setHorizontalAlignment(JLabel.CENTER);
                placeHolder.add(label, BorderLayout.CENTER);
                placeHolder.setPreferredSize(new Dimension(format.getWidth(), format.getHeight()));
                add(placeHolder, BorderLayout.CENTER);
    
                pack();
                setLocationRelativeTo(null);
                setVisible(true);
    
                startCapture();
            }
    
    
            public void initCapture() throws CaptureException
            {
                system = factory.createCaptureSystem();
                system.init();
                List list = system.getCaptureDeviceInfoList();
                int index = list.size() - 1;
    
                for (Object o : list)
                {
                    CaptureDeviceInfo info = (CaptureDeviceInfo) o;
                    System.out.println("==========================================================================");
                    System.out.println("  Available Device ID: " + info.getDeviceID());
                    System.out.println("  Available Description: " + info.getDescription());
                    System.out.println();
                }
    
                CaptureDeviceInfo info = (CaptureDeviceInfo) list.get(index);
                System.out.println("Using Device ID: " + info.getDeviceID());
                System.out.println("Using Description: " + info.getDescription());
                captureStream = system.openCaptureDeviceStream(info.getDeviceID());
                captureStream.setObserver(new MyCaptureObserver());
            }
    
            public void startCapture() throws CaptureException
            {
                captureStream.start();
            }
    
            public void disposeCapture()
            {
                try
                {
                    disposing = true;
    
                    if (captureStream != null)
                    {
                        System.out.println("disposeCapture: stopping capture stream...");
                        captureStream.stop();
                        System.out.println("disposeCapture: stopped capture stream.");
                        captureStream.dispose();
                        captureStream = null;
                    }
    
                    if (system != null)
                    {
                        system.dispose();
                    }
                    System.out.println("disposeCapture done.");
                }
                catch (CaptureException e)
                {
                    System.out.println("Error disposing capture");
                    e.printStackTrace();
                }
            }
    
    
            class MyCaptureObserver implements CaptureObserver
            {
                public void onError(CaptureStream sender, CaptureException e)
                {
                    e.printStackTrace();
                }
    
    
                public void onNewImage(CaptureStream sender, com.lti.civil.Image image)
                {
                    if (disposing)
                    {
                        return;
                    }
                    try
                    {
                        lastImage = AWTImageConverter.toBufferedImage(image);
                        setImage(lastImage);
                    }
                    catch (Throwable t)
                    {
                        t.printStackTrace();
                    }
                }
    
            }
        }
    }
  • 3. Re: How to control a webcam in JFX app?
    870239 Newbie
    Currently Being Moderated
    Thank you guys for quick answers!

    And special thanks to zonski, I think that is pretty much what I need and I will take closer look it.

    BR,
    Kasperi
  • 4. How about making use of VideoInput Library to support a webcam
    TadashiOhmura Newbie
    Currently Being Moderated
    Hello everyone

    How about making use of VideoInput Library to support a webcam on Windows platform.
    It is a useful library based on DirectShow written with C++.

    It opens the source code.
    It makes us to use webcam easily.

    Currently OpenCV project also use it.

    I have developed a simple Java application by using VideoInput Library via JNI.


    videoInput - a free windows video capture library
    http://muonics.net/school/spring05/videoInput/

    source code is here :
    http://muonics.net/school/spring05/videoInput/files/videoInput0.1995.zip

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points