Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with webcam lock #253

Closed
dsethu opened this issue Aug 14, 2014 · 5 comments
Closed

Issue with webcam lock #253

dsethu opened this issue Aug 14, 2014 · 5 comments

Comments

@dsethu
Copy link

dsethu commented Aug 14, 2014

Hi,

This was the same issue raised by 6thSense as #131.

Issue with the webcam lock.

I am accessing a webcam through the applet in a web application.

  • for the first time, I read the image. Save the image through applet to servlet communication using a custom object (Serialisation).
  • Close the webcam window (which will close the applet). In the applet stop method, code used is this.
    if (webcam.isOpen()) {
        webcam.close();
    }

Re-open the webcam window the second time immediately.

  • Wait for more than 2 seconds, click the start camera button, nothing happens it hangs.

I have enabled the java console in my machine to check if any errors are thrown from the applet.
Sometimes when the webcam window is opened, java console window is also opened, click the start camera button, camera opens and able to see the image.

You had kindly suggested to use this code to disable the lock mechanism.

Webcam w = Webcam.getDefault();
w.getLock().disable();

Tried to access the jar file,

https://oss.sonatype.org/content/repositories/snapshots/com/github/sarxos/webcam-capture/0.3.10-SNAPSHOT/webcam-capture-0.3.10-20130805.213713-14.jar

Got the error message when tried to access the link.

404 - Path /com/github/sarxos/webcam-capture/0.3.10-SNAPSHOT/webcam-capture-0.3.10-20130805.213713-14.jar not found in local storage of repository "Snapshots" [id=snapshots]
Path /com/github/sarxos/webcam-capture/0.3.10-SNAPSHOT/webcam-capture-0.3.10-20130805.213713-14.jar not found in local storage of repository "Snapshots" [id=snapshots]

When i used this code in my applet, shows compilation error

---------- Java1.6_Compile ----------
D:\Applications\Sample\WebCamImage\Source\PatientPhotoPanel.java:147: cannot find symbol
symbol  : method disable()
location: class com.github.sarxos.webcam.WebcamLock
        webcam.getLock().disable();
                        ^
1 error
Normal Termination
Output completed (0 sec consumed).

I use the webcam-capture-0.3.10-RC4-dist.zip, does the jar in the distribution has the code for this method disable.

While closing the webcam window, i am also getting the stack trace as shown here.

Aug 14, 2014 12:59:52 PM com.github.sarxos.webcam.WebcamExceptionHandler uncaughtException
SEVERE: Exception in thread webcam-updater-thread-1
java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source)
    at java.util.concurrent.locks.ReentrantLock.unlock(Unknown Source)
    at java.util.concurrent.LinkedBlockingQueue.take(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Aug 14, 2014 12:59:52 PM com.github.sarxos.webcam.WebcamExceptionHandler uncaughtException
SEVERE: Exception in thread atomic-processor-1
java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source)
    at java.util.concurrent.locks.ReentrantLock.unlock(Unknown Source)
    at java.util.concurrent.LinkedBlockingQueue.take(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

Kindly let me know as how I can avoid this issue with webcam getting locked and to avoid the error.

Thanks.

@dsethu
Copy link
Author

dsethu commented Aug 14, 2014

Hi,
Tried using webcam-capture-0.3.10-RC7-dist.zip file, compilation errors have gone.
Still getting the webcam hang error and the stack trace log when closing the webcam window.

Kindly check and let me know as how this could be solved.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.BorderFactory; 
import javax.swing.border.Border;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.table.DefaultTableModel;

import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.ArrayList;
import java.net.*;
import java.io.*;
import java.util.zip.*;
import java.awt.image.BufferedImage;

import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.imageio.ImageIO;

import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamLock;
import com.github.sarxos.webcam.WebcamPanel;
import com.github.sarxos.webcam.WebcamResolution;

import eMP.PatientPhoto.PatientPhotoComponent;

public class PatientPhotoPanel extends JPanel implements ActionListener {
    private int newNodeSuffix = 1;
    private static String START_COMMAND = "START";
    private static String CAPTURE_COMMAND = "CAPTURE";
    private static String SAVE_COMMAND = "SAVE";
    private static String CLEAR_COMMAND = "CLEAR";

    private static final long serialVersionUID = -5302010108271068350L;

    BufferedImage image =  null;    
    ImgDisplayPanel imagePanel;

    JFrame frame; 
    JTextField patientIdText;

    JButton startButton, captureButton, saveButton,  clearButton = null;

    Object listImage =  null;   

    URL urlServlet;
    String patient_id = "";

    int width;
    int height;

    private Dimension size = WebcamResolution.QVGA.getSize();   
    private Webcam webcam = null;   
    private WebcamPanel liveImagePanel = null;  

    public PatientPhotoPanel(URL url, String patientId) {

        super(new GridLayout(1,3));

        this.urlServlet = url;
        this.patient_id = patientId;

        Border loweredbevel;

        loweredbevel = BorderFactory.createLoweredBevelBorder();

        // Patient Panel
        GridLayout patientLayout = new GridLayout(1,2);
        JPanel patientPanel = new JPanel();
        patientPanel.setLayout(patientLayout);
        patientPanel.setSize(200, 80);

        //patientPanel.setPreferredSize(new Dimension(350, 50));
        patientPanel.add(new Label("Patient ID: "));
        patientIdText = new JTextField(patientId, 12);
        patientIdText.setEditable(false);
        patientPanel.add(patientIdText);        

        patientPanel.setBorder(BorderFactory.createLineBorder (Color.GRAY, 2));

        // Button Panel     
        GridLayout buttonLayout = new GridLayout(1,4);
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(buttonLayout);
        //buttonPanel.setPreferredSize(new Dimension(350, 80));
        buttonPanel.setSize(350,100);

        startButton = new JButton("Start Camera");
        startButton.setPreferredSize(new Dimension(80, 40));
        startButton.setActionCommand(START_COMMAND);
        startButton.addActionListener(this);
        buttonPanel.add(startButton);

        captureButton = new JButton("Capture Image");
        captureButton.setPreferredSize(new Dimension(100, 40));
        captureButton.setEnabled(false);
        captureButton.setActionCommand(CAPTURE_COMMAND);
        captureButton.addActionListener(this);
        buttonPanel.add(captureButton);

        saveButton = new JButton("Save Image");
        saveButton.setPreferredSize(new Dimension(80, 40));
        saveButton.setEnabled(false);
        saveButton.setActionCommand(SAVE_COMMAND);
        saveButton.addActionListener(this);
        buttonPanel.add(saveButton);    

        clearButton = new JButton("Clear Image");
        clearButton.setPreferredSize(new Dimension(80, 40));
        clearButton.setEnabled(false);
        clearButton.setActionCommand(CLEAR_COMMAND);
        clearButton.addActionListener(this);
        buttonPanel.add(clearButton);   

        //Set up the horizontal gap value
        buttonLayout.setHgap(50);
        //Set up the vertical gap value
        buttonLayout.setVgap(50);
        //Set up the layout of the buttons
        buttonLayout.layoutContainer(buttonPanel);

        buttonPanel.setBorder(BorderFactory.createLineBorder (Color.GRAY, 2));  

        // Image Panel      

        // Preview Image Panel
        imagePanel = new ImgDisplayPanel();
        imagePanel.setPreferredSize(new Dimension(320, 240));
        imagePanel.setBorder(BorderFactory.createLineBorder (Color.GRAY, 1));

        // live Image Panel
        webcam = Webcam.getDefault();
        webcam.getLock().disable();
        webcam.setViewSize(new Dimension(320, 240));
        liveImagePanel = new WebcamPanel(webcam, false);
        liveImagePanel.setFPSDisplayed(true);
        liveImagePanel.setBorder(BorderFactory.createLineBorder (Color.GRAY, 1));

        JPanel imageBoxPanel = new JPanel(new FlowLayout());
        imageBoxPanel.add(imagePanel);
        imageBoxPanel.add(liveImagePanel);
        //imageBoxPanel.setPreferredSize(new Dimension(640, 240));
        //imageBoxPanel.setSize(640, 250);
        imageBoxPanel.setVisible(true);
        imageBoxPanel.setBorder(BorderFactory.createLineBorder (Color.GRAY, 2));

        final JPanel compsToExperiment = new JPanel(new BorderLayout());

        compsToExperiment.add(patientPanel, BorderLayout.PAGE_START);
        compsToExperiment.add(imageBoxPanel, BorderLayout.CENTER);
        compsToExperiment.add(buttonPanel, BorderLayout.PAGE_END);

        imageBoxPanel.setBorder(BorderFactory.createLineBorder (Color.GRAY, 2));

        add(compsToExperiment);
    }

    public void actionPerformed(ActionEvent ae){        

        String command = ae.getActionCommand(); 

        System.out.println(" * * * Command * * * "+command);

        if (START_COMMAND.equals(command)) {
            //CAPTURE button clicked            
            StartCamera();          
            captureButton.setEnabled(true);
            saveButton.setEnabled(false);
            clearButton.setEnabled(false);          
        } else if (CAPTURE_COMMAND.equals(command)) {
            //CAPTURE button clicked
            Capture();                  
            imagePanel.setImage(image);
            imagePanel.repaint();
            captureButton.setEnabled(true);
            saveButton.setEnabled(true);
            clearButton.setEnabled(true);
            //validate();
            repaint();
        } else if (SAVE_COMMAND.equals(command)) {
            //SAVE button clicked
            onSendData(image);
            captureButton.setEnabled(false);
            saveButton.setEnabled(false);
            clearButton.setEnabled(false);
        } else if (CLEAR_COMMAND.equals(command)) {
            //Clear button clicked.
            clearImage();
            saveButton.setEnabled(false);
            clearButton.setEnabled(false);
            repaint();           
        }
    }   

    public void StartCamera() {

        System.out.println(" * * * Start Camera * * * ");

        if (webcam.isOpen()) {
            return;
        }

        int i = 0;
        do {
            if (webcam.getLock().isLocked()) {
                System.out.println("Waiting for lock to be released " + i);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e1) {
                    return;
                }
            } else {
                break;
            }
        } while (i++ < 3);

        webcam.open();
        liveImagePanel.start();
    }

    public void StopCamera() {

        System.out.println(" * * * Stop Camera * * * ");

        if (webcam.isOpen()) {
            webcam.close();
        }
    }

    public void CloseCamera() {

        System.out.println(" * * * destroy Camera * * * ");
        if (webcam.isOpen()) {
            webcam.close();
        }
        liveImagePanel.stop();
    }

    public void Capture() {

        System.out.println(" * * * Inside Capture 1 * * * ");

        //webcam = Webcam.getDefault();
        //webcam.open();
        image = webcam.getImage();      

    }   

    public void update(Graphics g) {

        if (image!=null) {
            imagePanel.setImage(image);
            imagePanel.repaint();
        } else {
            super.update(g);
        }

    }

    public String fileName(){
        String formattedDate = "";
        Date now = new Date();
        SimpleDateFormat df = new SimpleDateFormat("ddMMyyyykkmmss");
        df.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
        formattedDate = df.format(new Date());

        return formattedDate;
    }


    public void clearImage() {

        System.out.println(" * * * Inside Clear Image * * * ");

        imagePanel.setImage(null);
        imagePanel.validate();
        imagePanel.repaint(); 
    }

    /*
    public void paint (Graphics g) {
        update(g);
    }
    */

    public void paintComponents(Graphics g)
    {       
        //super.paintComponents(g);
        update(g);
        //g.drawImage(image, 350,0,this.getSize().width,this.getSize().height, this);       
        //g.drawImage(image, 0,0,null);         
    }

    /**
     * Get a connection to the servlet.
     */
    private URLConnection getServletConnection(URL urlServlet)
        throws MalformedURLException, IOException {

    URLConnection con = urlServlet.openConnection();

     con.setDoInput(true);
        con.setDoOutput(true);
        con.setUseCaches(false);
        con.setRequestProperty(
        "Content-Type",
        "application/octet-stream");

        return con;
    }

    /**
     * Send the inputField data to the servlet and show the result in the outputField.
     */
    private void onSendData(BufferedImage image) {
        try {

            width = image.getWidth();
            height = image.getHeight();

            int data[][] = new int[width][height];

            for (int w=0; w<width; w++)
                for (int h=0; h<height; h++)
                    data[w][h] = image.getRGB(w,h);

            URLConnection con = getServletConnection(urlServlet);

            PatientPhotoComponent image1 = new PatientPhotoComponent(patient_id, data);

            OutputStream outstream = con.getOutputStream();
            //ObjectOutputStream oos = new ObjectOutputStream(new GZIPOutputStream(outstream, 512*1024));
            //oos.writeObject(data);

            ObjectOutputStream oos = new ObjectOutputStream(outstream);
            oos.writeObject(image1);

            //JOptionPane.showMessageDialog(null," oos : "+oos);

            oos.flush();
            oos.close();

            // receive result from servlet
            InputStream instr = con.getInputStream();
            ObjectInputStream inputFromServlet = new ObjectInputStream(instr);
            String result = (String) inputFromServlet.readObject();
            inputFromServlet.close();
            instr.close();

            JOptionPane.showMessageDialog(null,result);

            clearImage();
            webcam.close();

        } catch (Exception ex) {
            webcam.close();
            ex.printStackTrace();
            JOptionPane.showMessageDialog(null,ex);
        }
    }
}

@dsethu
Copy link
Author

dsethu commented Aug 14, 2014

Stack Trace shown when the applet window is closed.

Aug 14, 2014 2:15:00 PM com.github.sarxos.webcam.WebcamExceptionHandler uncaughtException
SEVERE: Exception in thread atomic-processor-1
java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source)
    at java.util.concurrent.locks.ReentrantLock.unlock(Unknown Source)
    at java.util.concurrent.LinkedBlockingQueue.take(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Aug 14, 2014 2:15:00 PM com.github.sarxos.webcam.WebcamExceptionHandler uncaughtException
SEVERE: Exception in thread webcam-discovery-service
java.lang.ThreadDeath
    at java.lang.Thread.stop(Unknown Source)
    at java.lang.ThreadGroup.stopOrSuspend(Unknown Source)
    at java.lang.ThreadGroup.stop(Unknown Source)
    at sun.awt.AppContext.dispose(Unknown Source)
    at sun.plugin2.applet.Plugin2Manager$AppContextDisposer.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

@sarxos
Copy link
Owner

sarxos commented Aug 14, 2014

Hi,

  1. Don't mess with webcam lock - just leave it be and wait for it to be released. It has been designed for users safety. Before the lock feature has been created people reported many segmentation faults and Java VM crashed because of the invalid way of how Windows is using webcam.
  2. Check the Webcam Capture Applet Example. I tested it on Windows and Linux some time ago and haven't found any issues.
  3. In applet HTML code use <param name="separate_jvm" value="true" /> or you will get IllegalMonitorStateException errors from the executors.
  4. The always active snapshot link for newest 0.3.10 (same as on the main page, some hang issues has been fixed lately which are not available in RC7):

https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=com.github.sarxos&a=webcam-capture&v=0.3.10-SNAPSHOT

@dsethu
Copy link
Author

dsethu commented Aug 14, 2014

Hi Sarxos,

Thanks a lot. it worked with the separate jvm param tag added to the applet code in the JSP page.

Just to know the detail, could you let let me know as how the separate JVM parameter set to true works here in this context.

Thanks.

@sarxos
Copy link
Owner

sarxos commented Aug 14, 2014

When you close the applet in browser it behaves in unexpected manner - Java close executors and stop threads, so when you re-run the page and spawn new applet, the VM instance is the same - with static fields already initialized, with stopped executors, dead threads - it is essentially broken. To re-spawn the applet we would need another static initialization (<cinit>), but this is not possible without creating new ClassLoader. Java 6 update 10 introduced separate_jvm parameter to tells the applet to start every time in separate VM, which w/a our needs for another static initialization.

@sarxos sarxos closed this as completed Aug 14, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants