AudioClip volume problems - java

I watched a great tutorial of Mattew on how to implement audio sounds in Java games.
The problem is that even after I decreased the volume of the wav file when I run the game the volume of the wav sound file is still very high in Java, I mean you can't even play the game because of the background music that is too loud.
Why the volume of the wav file is not maintaining in Java?

It is probably better to use the Java Sound based Clip than the applet based AudioClip. The Clip interface supports controls, one of which should be a MASTER_GAIN.
E.G.
import java.awt.*;
import java.net.URL;
import javax.swing.*;
import javax.swing.event.*;
import javax.sound.sampled.*;
class ClipVolume {
public static void main(String[] args) throws Exception {
URL url = new URL(
"http://pscode.org/media/leftright.wav");
final Clip clip = AudioSystem.getClip();
// getAudioInputStream() also accepts a File or InputStream
AudioInputStream ais = AudioSystem.getAudioInputStream(url);
clip.open(ais);
clip.loop(Clip.LOOP_CONTINUOUSLY);
Runnable r = new Runnable() {
#Override
public void run() {
final FloatControl control = (FloatControl)
clip.getControl(FloatControl.Type.MASTER_GAIN);
final JSlider volume = new JSlider(
JSlider.HORIZONTAL,
(int) control.getMinimum(),
(int) control.getMaximum(),
(int) control.getValue());
volume.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent ce) {
control.setValue(volume.getValue());
}
});
JOptionPane.showMessageDialog(null, volume);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}

So, this is the code that i'm using, is working and hope that will help others as well.
happy coding and once again thanks to Andrew Thompson
package com.stefanbanu;
import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
// To play sound using Clip, the process need to be alive.
// Hence, we use a Swing application.
public class SoundClipTest extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
// Constructor
public SoundClipTest() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Test Sound Clip");
this.setSize(300, 200);
this.setVisible(true);
try {
// Open an audio input stream.
URL url = this.getClass().getClassLoader().getResource("bgsong.wav");
AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
// Get a sound clip resource.
Clip clip = AudioSystem.getClip();
// Open audio clip and load samples from the audio input stream.
clip.open(audioIn);
clip.start();
final FloatControl control = (FloatControl)
clip.getControl(FloatControl.Type.MASTER_GAIN);
control.setValue(-30.0f);
// final JSlider volume = new JSlider(
// JSlider.HORIZONTAL,
// (int) control.getMinimum(),
// (int) control.getMaximum(),
// (int) control.getValue());
// volume.addChangeListener(new ChangeListener() {
//
// public void stateChanged(ChangeEvent ce) {
// control.setValue(volume.getValue());
// }
// });
//
// JOptionPane.showMessageDialog(null, volume);
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new SoundClipTest();
}
}

Related

Draw profile of the mic input

I don't know much about sounds digitalization. I am trying to represent the instant profile of the mic input. I know how to get the bits from the mic, but I don't know how to interpret it into a profile. Can anyone help me filling the blank?
package test;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.io.OutputStream;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/**
*
* #author François Billioud
*/
public class SoundRecorder extends JFrame {
/** JFrame for the GUI **/
public SoundRecorder() {
super("Sound Recorder");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = getContentPane();
pane.setLayout(new BorderLayout());
pane.add(wavePane = new WavePane(), BorderLayout.CENTER);
pane.add(new JButton(new AbstractAction("ok") {
#Override
public void actionPerformed(ActionEvent e) {
dispose();
}
}), BorderLayout.SOUTH);
setSize(300,300);
setLocationRelativeTo(null);
}
/** Just displays the frame and starts listening **/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
SoundRecorder rec = new SoundRecorder();
rec.setVisible(true);
rec.listenToMic();
}
});
}
/** Draws the sound read from the mic **/
private static class WavePane extends JPanel {
private final int[] x = new int[0];
private int[] y = new int[0];
private WavePane() {
setOpaque(true);
setBackground(Color.WHITE);
}
/** updates the data to be displayed **/
public void setData(int[] y) {
this.y = y;
int n = y.length;
this.x = new int[n];
float pas = getWidth()/(float)(n-1);
float xCurrent = 0;
for(int i=0; i<n; i++) {
this.x[i] = Math.round(xCurrent);
xCurrent+=pas;
}
repaint();
}
/** Draws a line that represent the mic profile **/
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2D = (Graphics2D) g;
g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2D.drawPolyline(x, y, x.length);
}
}
/** Defines the audio format to be used.
* I know nothing about that and am open to suggestions if needed
*/
private static final AudioFormat format = new AudioFormat(
16000, //Sample rate
16, //SampleSizeInBits
2, //Channels
true,//Signed
true //BigEndian
);
/** Creates a thread that will read data from
* the mic and send it to the WavePane
* in order to be painted.
* We should be using a SwingWorker, but it will do
* for the sake of this demo.
**/
private void listenToMic() {
new Thread(new Runnable() {
#Override
public void run() {
try {
//Open the line and read
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
//checks if system supports the data line
if (!AudioSystem.isLineSupported(info)) {
System.err.print("Line not supported");
}
//starts listening
TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format);
line.start();
//sends the stream to the interpreter
AudioInputStream ais = new AudioInputStream(line);
AudioSystem.write(ais, AudioFileFormat.Type.AU, new Interpreter());
} catch (LineUnavailableException | IOException ex) {
System.err.println(ex.getLocalizedMessage());
}
}
}).start();
}
private final WavePane wavePane;
private class Interpreter extends OutputStream {
private int[] y;
#Override
public void write(int b) throws IOException {
//TBD
//Fill y array
}
#Override
public void flush() throws IOException {
//Sends the values found to the panel for drawing
wavePane.setData(y);
}
}
}
I found this link but it didn't help me...
Edit: Ok, from what I understand, each 16 bits is the amplitude for one frequency. I have 2 channels, so I have to read 16 bits every 32 to get the first channel. Now I need to know how many frequencies I am going to read for each frame. Then I think I can draw the profile. Any hint?
If you want to draw the spectrum (energy per frequency over time) of the signal that is coming from the microphone then you might want to read this. Maybe a bit more that you wanted to know but it has the maths you need.
If you want to draw the amplitude (the pressure over time) then check, for instance, this.
The contents of the audio stream, based on your specification of the audio format, will be a PCM stream. PCM stream means that every frame is a value of sound pressure at that moment of time. Each frame will consist of four bytes, two bytes per channel. The first two bytes will be channel 0, the other two -- channel 1. The two bytes will be in big endian format (the more significant byte will come before the less significant byte). The fact that you specified signed as True means that you should interpret the values as being in the range from -32768 to 32767.

fileName cannot be found in addActionListener, JAVA

I'm trying to make a function to play an audio when an user clicks a button. The problem is that when I tried to pass in the fileName from the parameter using "fileName.addActionListener", it says that fileName cannot be found even though it's referenced in the parameter. What did I do wrong, and how can I fix this? Thanks.
package sunaudiodemo;
import static java.awt.Color.blue;
import static java.awt.Color.green;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import sun.audio.*; //import the sun.audio package
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
public class SunAudioDemo {
public static void playAudioOnClick (final String fileName) {
//*******************************************
fileName.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
playAudio(fileName);
} catch (Exception ex) {
Logger.getLogger(SunAudioDemo.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
//*******************************************
}
public static void playAudio (String text) throws Exception {
// identify the sound file as a File class object
File soundFile = new File(text);
// Open an input stream for the File object soundFile
// This allows Java to read the file.
InputStream inFile = new FileInputStream(soundFile);
// Create an AudioStream from the input stream.
// This tells Java to read the incoming data as sound data.
AudioStream audio = new AudioStream(inFile);
// play the sound file using the start method from Audioplayer.player
AudioPlayer.player.start(audio);
}
public static void main(String[] args) throws Exception {
// create a frame to hold our components
JFrame myJFrame = new JFrame();
// create a new a grid layout for the frame - 5 rows x 2 cols, gaps=20
GridLayout myLayout = new GridLayout(5,2);
myLayout.setHgap(20);
myLayout.setVgap(20);
// assign myLayout to be the layout for MyJFrame
myJFrame.setLayout(myLayout);
// Create a button with text OK
JButton wav1 = new JButton("Play Audio 1");
myJFrame.add(wav1); // Add the OK button
playAudioOnClick("wav2.wav");
// set the title, size, location and exit behavior for the JFrame
myJFrame.setTitle("Play Audio");
myJFrame.setSize(360, 480);
myJFrame.setLocation(200, 100);
myJFrame.getContentPane().setBackground( green );
myJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// make the frame visible (activate the frame)
myJFrame.setVisible(true);
} // end main()
} // end class SunAudioDemo
In the code above, fileName is defined as a String. Assuming this is java.lang.String, there is no method addActionListener(). You need to pass in a reference to your button so you can add the ActionListener to it.

Java - Playing a sound on top of background music

This is my first time posting, and hopefully I'm posting correctly.
I'm currently playing a background song for my project, and I'm trying to play a sound effect, when a button is pressed, on top of the background song. However, the sound doesn't play and the bgm just continues. See below for my Audio class (ignore the bad commenting), and thanks in advance for the help.
package pro;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class Audio
{
private boolean loop = false;
private AudioInputStream ais = null;
private static Clip clip = null;
//declaration of variables
public Audio (String fileName, boolean loop)
//Constructor for the class which fileName and accepts whether the clip needs to loop or not
{
this.loop = loop;
//sets the variable within the class as constructor
try {
clip = AudioSystem.getClip();
ais = AudioSystem.getAudioInputStream(Audio.class.getResource(fileName));
clip.open(ais);
} catch (IOException | UnsupportedAudioFileException | LineUnavailableException e) {
e.printStackTrace();
}
//tries to load file into java's built in audio player, else prints the error to console
}
public void musicStart ()
//starts music
{
if (loop)
{
clip.loop(Clip.LOOP_CONTINUOUSLY);
//starts music on loop if loop is requested
}
else
{
clip.start();
//starts music as not on loop
}
}
public void musicStop ()
//stops the music
{
clip.stop();
}
}
EDIT: I found a solution to the problem thanks to MadProgrammer by simply removing static from clip.
Get rid of the static declaration of the Clip. Each instance of Audio should be self contained and point to it's own instance of Clip
Basically, the static will make Clip ALWAYS point to the last sound file loaded, this isn't really what you want, because when you call stopMusic, you won't know which clip you're really stopping or if you're actually stopping anything at all

Can Java Sound be used to control the system volume?

Java Sound offers FloatControl instances for various sound line functionality, and both a MASTER_GAIN & VOLUME control type.
Can these controls be used to change the system volume?
No, it cannot. Here is source adapted from an answer to Adjusting master volume on coderanch. The source iterates the available lines, checks if they have a control of the right type, and if so, puts them in a GUI attached to a JSlider
import java.awt.*;
import javax.swing.*;
import javax.sound.sampled.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class SoundMixer {
public Component getGui() {
JPanel gui = new JPanel(new GridLayout(0,1));
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
System.out.println(
"There are " + mixers.length + " mixer info objects");
for (Mixer.Info mixerInfo : mixers) {
System.out.println("mixer name: " + mixerInfo.getName());
Mixer mixer = AudioSystem.getMixer(mixerInfo);
Line.Info[] lineInfos = mixer.getSourceLineInfo();
for (Line.Info lineInfo : lineInfos) {
System.out.println(" Line.Info: " + lineInfo);
try {
Line line = mixer.getLine(lineInfo);
FloatControl volCtrl = (FloatControl)line.getControl(
FloatControl.Type.MASTER_GAIN);
VolumeSlider vs = new VolumeSlider(volCtrl);
gui.add( new JLabel(volCtrl.toString()) );
gui.add( vs.getVolume() );
System.out.println(
" volCtrl.getValue() = " + volCtrl.getValue());
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (IllegalArgumentException iaEx) {
System.out.println(" " + iaEx);
}
}
}
return gui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
SoundMixer sm = new SoundMixer();
Component c = sm.getGui();
JOptionPane.showMessageDialog(null, c);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
class VolumeSlider {
JSlider volume;
VolumeSlider(final FloatControl volumeControl) {
volume = new JSlider(
(int) volumeControl.getMinimum() * 100,
(int) volumeControl.getMaximum() * 100,
(int) volumeControl.getValue() * 100);
ChangeListener listener = new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
float val = volume.getValue() / 100f;
volumeControl.setValue(val);
System.out.println(
"Setting volume of " + volumeControl.toString() +
" to " + val);
}
};
volume.addChangeListener(listener);
}
public JSlider getVolume() {
return volume;
}
}
On this Windows 7 machine I get two controls, both from the "Java Sound Audio Engine". Neither has any effect on the current system volume.
run:
There are 4 mixer info objects
mixer name: Primary Sound Driver
Line.Info: interface SourceDataLine supporting 8 audio formats, and buffers of at least 32 bytes
java.lang.IllegalArgumentException: Unsupported control type: Master Gain
Line.Info: interface Clip supporting 8 audio formats, and buffers of at least 32 bytes
java.lang.IllegalArgumentException: Unsupported control type: Master Gain
mixer name: Speakers (VIA High Definition Audio)
Line.Info: interface SourceDataLine supporting 8 audio formats, and buffers of at least 32 bytes
java.lang.IllegalArgumentException: Unsupported control type: Master Gain
Line.Info: interface Clip supporting 8 audio formats, and buffers of at least 32 bytes
java.lang.IllegalArgumentException: Unsupported control type: Master Gain
mixer name: Java Sound Audio Engine
Line.Info: interface SourceDataLine supporting 8 audio formats
volCtrl.getValue() = 0.0
Line.Info: interface Clip supporting 8 audio formats, and buffers of 0 to 4194304 bytes
volCtrl.getValue() = 0.0
mixer name: Port Speakers (VIA High Definition A
Setting volume of Master Gain with current value: 0.0 dB (range: -80.0 - 13.9794) to 0.0
Setting volume of Master Gain with current value: 0.0 dB (range: -80.0 - 13.9794) to -0.41
Setting volume of Master Gain with current value: 0.0 dB (range: -80.0 - 13.9794) to -0.68
...
Swap FloatControl.Type.MASTER_GAIN for FloatControl.Type.VOLUME to see.. no controls.
add following line just after Line is initialized. this is required to open the line.
boolean opened = line.isOpen() || line instanceof Clip;
if(!opened){
System.out.println("Line is not open, trying to open it...");
line.open();
opened = true;
}
try this it wont disappoint you.... we can modify upper example accordingly.
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
public class SoundMeter {
JFrame j;
public SoundMeter() {
j = new JFrame("SoundMeter");
j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
j.setLayout(new BoxLayout(j.getContentPane(), BoxLayout.Y_AXIS));
printMixersDetails();
j.setVisible(true);
}
public void printMixersDetails(){
javax.sound.sampled.Mixer.Info[] mixers = AudioSystem.getMixerInfo();
System.out.println("There are " + mixers.length + " mixer info objects");
for(int i=0;i<mixers.length;i++){
Mixer.Info mixerInfo = mixers[i];
System.out.println("Mixer Name:"+mixerInfo.getName());
Mixer mixer = AudioSystem.getMixer(mixerInfo);
Line.Info[] lineinfos = mixer.getTargetLineInfo();
for(Line.Info lineinfo : lineinfos){
System.out.println("line:" + lineinfo);
try {
Line line = mixer.getLine(lineinfo);
line.open();
if(line.isControlSupported(FloatControl.Type.VOLUME)){
FloatControl control = (FloatControl) line.getControl(FloatControl.Type.VOLUME);
System.out.println("Volume:"+control.getValue());
JProgressBar pb = new JProgressBar();
// if you want to set the value for the volume 0.5 will be 50%
// 0.0 being 0%
// 1.0 being 100%
control.setValue((float) 0.5);
int value = (int) (control.getValue()*100);
pb.setValue(value);
j.add(new JLabel(lineinfo.toString()));
j.add(pb);
j.pack();
}
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
new SoundMeter();
}
}
I am using VOLUME control type. This code works for me for XP and WIN 7, but not for OSX. See my example:
import java.io.IOException;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.Line;
import javax.sound.sampled.Mixer;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class VolumeExample extends JPanel {
/**
* #return main sound control object
* #throws Exception for any problem
*/
private FloatControl getVolumeControl() throws Exception {
try {
Mixer.Info mixers[] = AudioSystem.getMixerInfo();
for (Mixer.Info mixerInfo : mixers) {
Mixer mixer = AudioSystem.getMixer(mixerInfo);
mixer.open();
//we check only target type lines, because we are looking for "SPEAKER target port"
for (Line.Info info : mixer.getTargetLineInfo()) {
if (info.toString().contains("SPEAKER")) {
Line line = mixer.getLine(info);
try {
line.open();
} catch (IllegalArgumentException iae) {}
return (FloatControl) line.getControl(FloatControl.Type.VOLUME);
}
}
}
} catch (Exception ex) {
System.out.println("problem creating volume control object:"+ex);
throw ex;
}
throw new Exception("unknown problem creating volume control object");
}
VolumeExample() {
JSlider slider = new JSlider();
add(slider);
//this is for setting the value
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
JSlider src = (JSlider)e.getSource();
//if (src.getValueIsAdjusting()) return; //optional
if (src.getValue() % 5 !=0) return;
float value = src.getValue() / 100.0f;
try {
getVolumeControl().setValue(value);
//you can put a click play code here to have nice feedback when moving slider
} catch (Exception ex) {
System.out.println(ex);
}
}
});
//and this is for getting the value
try {
slider.setValue((int) (getVolumeControl().getValue()*100.0f));
} catch (Exception e) {
System.out.println(e);
}
}
}
I was recently focusing the same problem. In the end I decided to write a little Program called VolumeChanger.exe in C++ and call this from java. Works great. You can call a exe from java with
Process process = new ProcessBuilder(vcpath,"-u").start();
wehre vcpath is the path to your exe file (could be realtive of course).
If you are interested how I used this tool visit me on muteFritz
If you are interested in the whole source code feel free to PM me...
Here is a solution that works ONLY on OS X (I am running 10.10):
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
public class MasterVolume
{
public void setMasterVolume(float value)
{
String command = "set volume " + value;
try
{
ProcessBuilder pb = new ProcessBuilder("osascript","-e",command);
pb.directory(new File("/usr/bin"));
System.out.println(command);
StringBuffer output = new StringBuffer();
Process p = pb.start();
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = reader.readLine())!= null)
{
output.append(line + "\n");
}
System.out.println(output);
}
catch(Exception e)
{
System.out.println(e);
}
}
}
You would call the method like this:
MasterVolume.setMasterVolume(3.5f);
Which would set the volume at 50% since the range is .1 to 7.0

Capturing image from webcam in java?

How can I continuously capture images from a webcam?
I want to experiment with object recognition (by maybe using java media framework).
I was thinking of creating two threads
one thread:
Node 1: capture live image
Node 2: save image as "1.jpg"
Node 3: wait 5 seconds
Node 4: repeat...
other thread:
Node 1: wait until image is captured
Node 2: using the "1.jpg" get colors
from every pixle
Node 3: save data in arrays
Node 4: repeat...
This JavaCV implementation works fine.
Code:
import org.bytedeco.javacv.*;
import org.bytedeco.opencv.opencv_core.IplImage;
import java.io.File;
import static org.bytedeco.opencv.global.opencv_core.cvFlip;
import static org.bytedeco.opencv.helper.opencv_imgcodecs.cvSaveImage;
public class Test implements Runnable {
final int INTERVAL = 100;///you may use interval
CanvasFrame canvas = new CanvasFrame("Web Cam");
public Test() {
canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
}
public void run() {
new File("images").mkdir();
FrameGrabber grabber = new OpenCVFrameGrabber(0); // 1 for next camera
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
IplImage img;
int i = 0;
try {
grabber.start();
while (true) {
Frame frame = grabber.grab();
img = converter.convert(frame);
//the grabbed frame will be flipped, re-flip to make it right
cvFlip(img, img, 1);// l-r = 90_degrees_steps_anti_clockwise
//save
cvSaveImage("images" + File.separator + (i++) + "-aa.jpg", img);
canvas.showImage(converter.convert(img));
Thread.sleep(INTERVAL);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Test gs = new Test();
Thread th = new Thread(gs);
th.start();
}
}
There is also post on configuration for JavaCV
You can modify the code and be able to save the images in regular interval and do rest of the processing you want.
Some time ago I've created generic Java library which can be used to take pictures with a PC webcam. The API is very simple, not overfeatured, can work standalone, but also supports additional webcam drivers like OpenIMAJ, JMF, FMJ, LTI-CIVIL, etc, and some IP cameras.
Link to the project is https://github.com/sarxos/webcam-capture
Example code (take picture and save in test.jpg):
Webcam webcam = Webcam.getDefault();
webcam.open();
BufferedImage image = webcam.getImage();
ImageIO.write(image, "JPG", new File("test.jpg"));
It is also available in Maven Central Repository or as a separate ZIP which includes all required dependencies and 3rd party JARs.
JMyron is very simple for use.
http://webcamxtra.sourceforge.net/
myron = new JMyron();
myron.start(imgw, imgh);
myron.update();
int[] img = myron.image();
Here is a similar question with some - yet unaccepted - answers. One of them mentions FMJ as a java alternative to JMF.
This kind of goes off of gt_ebuddy's answer using JavaCV, but my video output is at a much higher quality then his answer. I've also added some other random improvements (such as closing down the program when ESC and CTRL+C are pressed, and making sure to close down the resources the program uses properly).
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
import com.googlecode.javacv.CanvasFrame;
import com.googlecode.javacv.OpenCVFrameGrabber;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
public class HighRes extends JComponent implements Runnable {
private static final long serialVersionUID = 1L;
private static CanvasFrame frame = new CanvasFrame("Web Cam");
private static boolean running = false;
private static int frameWidth = 800;
private static int frameHeight = 600;
private static OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);
private static BufferedImage bufImg;
public HighRes()
{
// setup key bindings
ActionMap actionMap = frame.getRootPane().getActionMap();
InputMap inputMap = frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
for (Keys direction : Keys.values())
{
actionMap.put(direction.getText(), new KeyBinding(direction.getText()));
inputMap.put(direction.getKeyStroke(), direction.getText());
}
frame.getRootPane().setActionMap(actionMap);
frame.getRootPane().setInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW, inputMap);
// setup window listener for close action
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
stop();
}
});
}
public static void main(String... args)
{
HighRes webcam = new HighRes();
webcam.start();
}
#Override
public void run()
{
try
{
grabber.setImageWidth(frameWidth);
grabber.setImageHeight(frameHeight);
grabber.start();
while (running)
{
final IplImage cvimg = grabber.grab();
if (cvimg != null)
{
// cvFlip(cvimg, cvimg, 1); // mirror
// show image on window
bufImg = cvimg.getBufferedImage();
frame.showImage(bufImg);
}
}
grabber.stop();
grabber.release();
frame.dispose();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void start()
{
new Thread(this).start();
running = true;
}
public void stop()
{
running = false;
}
private class KeyBinding extends AbstractAction {
private static final long serialVersionUID = 1L;
public KeyBinding(String text)
{
super(text);
putValue(ACTION_COMMAND_KEY, text);
}
#Override
public void actionPerformed(ActionEvent e)
{
String action = e.getActionCommand();
if (action.equals(Keys.ESCAPE.toString()) || action.equals(Keys.CTRLC.toString())) stop();
else System.out.println("Key Binding: " + action);
}
}
}
enum Keys
{
ESCAPE("Escape", KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0)),
CTRLC("Control-C", KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK)),
UP("Up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)),
DOWN("Down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)),
LEFT("Left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)),
RIGHT("Right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
private String text;
private KeyStroke keyStroke;
Keys(String text, KeyStroke keyStroke)
{
this.text = text;
this.keyStroke = keyStroke;
}
public String getText()
{
return text;
}
public KeyStroke getKeyStroke()
{
return keyStroke;
}
#Override
public String toString()
{
return text;
}
}
You can try Java Webcam SDK library also.
SDK demo applet is available at link.
I have used JMF on a videoconference application and it worked well on two laptops: one with integrated webcam and another with an old USB webcam. It requires JMF being installed and configured before-hand, but once you're done you can access the hardware via Java code fairly easily.
You can try Marvin Framework. It provides an interface to work with cameras. Moreover, it also provides a set of real-time video processing features, like object tracking and filtering.
Take a look!
Real-time Video Processing Demo:
http://www.youtube.com/watch?v=D5mBt0kRYvk
You can use the source below. Just save a frame using MarvinImageIO.saveImage() every 5 second.
Webcam video demo:
public class SimpleVideoTest extends JFrame implements Runnable{
private MarvinVideoInterface videoAdapter;
private MarvinImage image;
private MarvinImagePanel videoPanel;
public SimpleVideoTest(){
super("Simple Video Test");
videoAdapter = new MarvinJavaCVAdapter();
videoAdapter.connect(0);
videoPanel = new MarvinImagePanel();
add(videoPanel);
new Thread(this).start();
setSize(800,600);
setVisible(true);
}
#Override
public void run() {
while(true){
// Request a video frame and set into the VideoPanel
image = videoAdapter.getFrame();
videoPanel.setImage(image);
}
}
public static void main(String[] args) {
SimpleVideoTest t = new SimpleVideoTest();
t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
For those who just want to take a single picture:
WebcamPicture.java
public class WebcamPicture {
public static void main(String[] args) {
try{
MarvinVideoInterface videoAdapter = new MarvinJavaCVAdapter();
videoAdapter.connect(0);
MarvinImage image = videoAdapter.getFrame();
MarvinImageIO.saveImage(image, "./res/webcam_picture.jpg");
} catch(MarvinVideoInterfaceException e){
e.printStackTrace();
}
}
}
I used Webcam Capture API. You can download it from here
webcam = Webcam.getDefault();
webcam.open();
if (webcam.isOpen()) { //if web cam open
BufferedImage image = webcam.getImage();
JLabel imageLbl = new JLabel();
imageLbl.setSize(640, 480); //show captured image
imageLbl.setIcon(new ImageIcon(image));
int showConfirmDialog = JOptionPane.showConfirmDialog(null, imageLbl, "Image Viewer", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, new ImageIcon(""));
if (showConfirmDialog == JOptionPane.YES_OPTION) {
JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("Save Image");
chooser.setFileFilter(new FileNameExtensionFilter("IMAGES ONLY", "png", "jpeg", "jpg")); //this file extentions are shown
int showSaveDialog = chooser.showSaveDialog(this);
if (showSaveDialog == 0) { //if pressed 'Save' button
String filePath = chooser.getCurrentDirectory().toString().replace("\\", "/");
String fileName = chooser.getSelectedFile().getName(); //get user entered file name to save
ImageIO.write(image, "PNG", new File(filePath + "/" + fileName + ".png"));
}
}
}
http://grack.com/downloads/school/enel619.10/report/java_media_framework.html
Using the Player with Swing
The Player can be easily used in a Swing application as well. The following code creates a Swing-based TV capture program with the video output displayed in the entire window:
import javax.media.*;
import javax.swing.*;
import java.awt.*;
import java.net.*;
import java.awt.event.*;
import javax.swing.event.*;
public class JMFTest extends JFrame {
Player _player;
JMFTest() {
addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent e ) {
_player.stop();
_player.deallocate();
_player.close();
System.exit( 0 );
}
});
setExtent( 0, 0, 320, 260 );
JPanel panel = (JPanel)getContentPane();
panel.setLayout( new BorderLayout() );
String mediaFile = "vfw://1";
try {
MediaLocator mlr = new MediaLocator( mediaFile );
_player = Manager.createRealizedPlayer( mlr );
if (_player.getVisualComponent() != null)
panel.add("Center", _player.getVisualComponent());
if (_player.getControlPanelComponent() != null)
panel.add("South", _player.getControlPanelComponent());
}
catch (Exception e) {
System.err.println( "Got exception " + e );
}
}
public static void main(String[] args) {
JMFTest jmfTest = new JMFTest();
jmfTest.show();
}
}
Java usually doesn't like accessing hardware, so you will need a driver program of some sort, as goldenmean said. I've done this on my laptop by finding a command line program that snaps a picture. Then it's the same as goldenmean explained; you run the command line program from your java program in the takepicture() routine, and the rest of your code runs the same.
Except for the part about reading pixel values into an array, you might be better served by saving the file to BMP, which is nearly that format already, then using the standard java image libraries on it.
Using a command line program adds a dependency to your program and makes it less portable, but so was the webcam, right?
I believe the web-cam application software which comes along with the web-cam, or you native windows webcam software can be run in a batch script(windows/dos script) after turning the web cam on(i.e. if it needs an external power supply). In the bacth script , u can add appropriate delay to capture after certain time period. And keep executing the capture command in loop.
I guess this should be possible
-AD
There's a pretty nice interface for this in processing, which is kind of a pidgin java designed for graphics. It gets used in some image recognition work, such as that link.
Depending on what you need out of it, you might be able to load the video library that's used there in java, or if you're just playing around with it you might be able to get by using processing itself.
FMJ can do this, as can the supporting library it uses, LTI-CIVIL. Both are on sourceforge.
Recommand using FMJ for multimedia relatived java app.
Try using JMyron How To Use Webcam Using Java. I think using JMyron is the easiest way to access a webcam using java. I tried to use it with a 64-bit processor, but it gave me an error. It worked just fine on a 32-bit processor, though.

Categories