Use camera to grab avatar image.

cusax-fix
Damian Minkov 16 years ago
parent 1b922e2a3c
commit dc0f19b870

@ -20,4 +20,6 @@ DIAL=resources/sounds/dial.wav
HANG_UP=resources/sounds/hangup.wav
CALL_SECURITY_ON=resources/sounds/zrtpSecure.wav
CALL_SECURITY_ERROR=resources/sounds/zrtpAlert.wav
CALL_SECURITY_ERROR=resources/sounds/zrtpAlert.wav
WEBCAM_SNAPSHOT=resources/sounds/webcamSnapshot.wav

@ -260,7 +260,8 @@ public void run()
= GuiActivator.getRegisteredProviderForAccount(
accountID);
if(protocolProvider != null)
if(protocolProvider != null
&& protocolProvider.isRegistered())
{
OperationSetAvatar opSetAvatar
= protocolProvider

@ -96,8 +96,6 @@ private void initComponents(int clipperZoneWidth, int clipperZoneHeight)
this.webcamButton = new JButton(GuiActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.TAKE_PHOTO"));
// disable it till we support it
this.webcamButton.setEnabled(false);
this.webcamButton.addActionListener(this);
this.webcamButton.setName("webcamButton");
@ -158,17 +156,17 @@ else if (name.equals("resetButton"))
{
this.editPanel.reset();
}
else
else if (name.equals("webcamButton"))
{
// WebcamDialog dialog = new WebcamDialog(this);
// dialog.setVisible(true);
// byte[] bimage = dialog.getGrabbedImage();
//
// if (bimage != null)
// {
// Image i = new ImageIcon(bimage).getImage();
// editPanel.setImage(ImageUtils.getBufferedImage(i));
// }
WebcamDialog dialog = new WebcamDialog(this);
dialog.setVisible(true);
byte[] bimage = dialog.getGrabbedImage();
if (bimage != null)
{
Image i = new ImageIcon(bimage).getImage();
editPanel.setImage(ImageUtils.getBufferedImage(i));
}
}
}

@ -8,36 +8,38 @@
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.service.audionotifier.*;
//import net.java.sip.communicator.service.media.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
/**
* A dialog showing the webcam and allowing the user to grap a snapshot
*
* @author Damien Roth
* @author Damian Minkov
*/
public class WebcamDialog
extends SIPCommDialog
implements ActionListener
// , VideoListener
{
/**
* The <tt>Logger</tt> used by the <tt>WebcamDialog</tt> class and its
* instances for logging output.
*/
private static final Logger logger = Logger.getLogger(WebcamDialog.class);
private VideoContainer videoContainer;
private Component videoComponent = null;
private JButton cancelButton;
private JButton grabSnapshot;
private byte[] grabbedImage = null;
private TransparentPanel southPanel;
private TransparentPanel timerPanel;
private TimerImage[] timerImages = new TimerImage[3];
/**
@ -66,40 +68,40 @@ private void init()
this.grabSnapshot.addActionListener(this);
this.grabSnapshot.setEnabled(false);
this.cancelButton = new JButton(GuiActivator.getResources()
JButton cancelButton = new JButton(GuiActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.CANCEL"));
this.cancelButton.setName("cancel");
this.cancelButton.addActionListener(this);
cancelButton.setName("cancel");
cancelButton.addActionListener(this);
initAccessWebcam();
// Timer Panel
this.timerPanel = new TransparentPanel();
this.timerPanel.setLayout(new GridLayout(0, 3));
TransparentPanel timerPanel = new TransparentPanel();
timerPanel.setLayout(new GridLayout(0, timerImages.length));
TransparentPanel tp;
for (int i = 0; i < this.timerImages.length; i++)
{
this.timerImages[i] = new TimerImage("" + (3-i));
this.timerImages[i] = new TimerImage("" + (timerImages.length - i));
tp = new TransparentPanel();
tp.add(this.timerImages[i], BorderLayout.CENTER);
this.timerPanel.add(tp);
timerPanel.add(tp);
}
TransparentPanel buttonsPanel = new TransparentPanel(new GridLayout(1, 2));
TransparentPanel buttonsPanel
= new TransparentPanel(new GridLayout(1, 2));
buttonsPanel.add(this.grabSnapshot);
buttonsPanel.add(this.cancelButton);
buttonsPanel.add(cancelButton);
// South Panel
this.southPanel = new TransparentPanel(new BorderLayout());
this.southPanel.add(this.timerPanel, BorderLayout.CENTER);
this.southPanel.add(buttonsPanel, BorderLayout.SOUTH);
TransparentPanel southPanel = new TransparentPanel(new BorderLayout());
southPanel.add(timerPanel, BorderLayout.CENTER);
southPanel.add(buttonsPanel, BorderLayout.SOUTH);
this.add(this.videoContainer, BorderLayout.CENTER);
this.add(this.southPanel, BorderLayout.SOUTH);
this.add(southPanel, BorderLayout.SOUTH);
}
/**
@ -107,46 +109,39 @@ private void init()
*/
private void initAccessWebcam()
{
Dimension d = new Dimension(320, 240);
// Create a container for the video
this.videoContainer = new VideoContainer(new JLabel(
GuiActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.INITIALIZING"),
JLabel.CENTER));
this.videoContainer.setPreferredSize(d);
this.videoContainer.setMinimumSize(d);
this.videoContainer.setMaximumSize(d);
// try
// {
// // Call the method in the media service
// GuiActivator.getMediaService().createLocalVideoComponent(this);
// } catch (MediaException e)
// {
// //todo: In what scenarios are exceptions thrown and how to manage them?
// this.videoContainer = new VideoContainer(new JLabel(
// GuiActivator.getResources()
// .getI18NString("service.gui.avatar.imagepicker.WEBCAM_ERROR")));
// e.printStackTrace();
// }
//Call the method in the media service
this.videoContainer =
(VideoContainer)GuiActivator.getMediaService()
.getVideoPreviewComponent(
GuiActivator.getMediaService().getDefaultDevice(
MediaType.VIDEO,
MediaUseCase.CALL
), 320, 240);
this.grabSnapshot.setEnabled(true);
}
/**
* Grap the current image of the webcam throught the MediaService
* Grab the current image of the webcam through the MediaService
*/
private void grabSnapshot()
{
// Just call the method "grabSnapshot" from the MediaService with the component
// try
// {
// this.grabbedImage = GuiActivator.getMediaService()
// .grabSnapshot(this.videoComponent);
// }
// catch (Exception e)
// {
// e.printStackTrace();
// }
try
{
Robot robot = new Robot();
Point location = videoContainer.getLocationOnScreen();
BufferedImage bi = robot.createScreenCapture(new Rectangle(
location.x,
location.y,
videoContainer.getWidth(),
videoContainer.getHeight()));
this.grabbedImage = ImageUtils.toByteArray(bi);
}
catch (Throwable e)
{
logger.error("Cannot create snapshot!", e);
}
close(false);
this.setVisible(false);
}
@ -177,41 +172,8 @@ private void playSound()
protected void close(boolean isEscaped)
{
// try
// {
// if (this.videoComponent != null)
// {
// GuiActivator.getMediaService()
// .disposeLocalVideoComponent(this.videoComponent);
// this.videoComponent = null;
// }
// }
// catch (MediaException e)
// {
// // Better manager the exception !
// e.printStackTrace();
// }
}
public void videoAdded(VideoEvent event)
{
// Here is the important part. With this event, you get the component
// containing the video !
// You need to keep it. The returned componant is the key for all
// the other methods !
this.videoComponent = event.getVisualComponent();
// Add the component in the container
this.videoContainer.add(this.videoComponent);
this.grabSnapshot.setEnabled(true);
}
public void videoRemoved(VideoEvent event)
{
// In case of the video is removed elsewhere
this.videoComponent = null;
this.videoContainer = null;
dispose();
}
public void actionPerformed(ActionEvent e)
@ -220,21 +182,21 @@ public void actionPerformed(ActionEvent e)
if (actName.equals("grab"))
{
if (this.videoComponent == null)
return;
this.grabSnapshot.setEnabled(false);
new SnapshotTimer().start();
}
else
{
close(false);
this.setVisible(false);
dispose();
}
}
/**
* This thread grabs the snapshot by counting down.
*/
private class SnapshotTimer
extends Thread
extends Thread
{
@Override
public void run()
@ -250,7 +212,7 @@ public void run()
}
catch (InterruptedException e)
{
e.printStackTrace();
logger.error("", e);
}
}
@ -262,7 +224,10 @@ public void run()
}
}
/**
* These are the images shown as timer while grabbing the snapshot.
*/
private class TimerImage
extends JComponent
{

@ -5,20 +5,21 @@
*/
package net.java.sip.communicator.impl.neomedia;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.media.*;
import javax.media.MediaException;
import javax.media.control.*;
import javax.media.protocol.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import net.java.sip.communicator.impl.neomedia.codec.video.*;
import net.java.sip.communicator.impl.neomedia.device.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.neomedia.device.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
@ -58,12 +59,6 @@ public class MediaConfiguration
*/
private static CaptureDeviceInfo videoDeviceInPreview;
/**
* The <code>Player</code> depicting the preview of the currently selected
* <code>CaptureDeviceInfo</code>.
*/
private static Player videoPlayerInPreview;
/**
* Returns the audio configuration panel.
* @return the audio configuration panel
@ -82,65 +77,6 @@ public static Component createVideoConfigPanel()
return createControls(DeviceConfigurationComboBoxModel.VIDEO);
}
/**
* Listens and shows the video in the video container when needed.
* @param event the event when player has ready visual component.
* @param videoContainer the container.
*/
private static void controllerUpdateForPreview(ControllerEvent event,
Container videoContainer)
{
if (event instanceof ConfigureCompleteEvent)
{
Processor player = (Processor) event.getSourceController();
/*
* Use SwScaler for the scaling since it produces an image with
* better quality.
*/
TrackControl[] trackControls = player.getTrackControls();
if ((trackControls != null) && (trackControls.length != 0))
try
{
for (TrackControl trackControl : trackControls)
{
SwScaler playerScaler = new SwScaler();
trackControl.setCodecChain(
new Codec[] { playerScaler });
break;
}
}
catch (UnsupportedPlugInException upiex)
{
logger.warn("Failed to add SwScaler to codec chain", upiex);
}
// Turn the Processor into a Player.
try
{
player.setContentDescriptor(null);
}
catch (NotConfiguredError nce)
{
logger.error(
"Failed to set ContentDescriptor of Processor",
nce);
}
player.realize();
}
else if (event instanceof RealizeCompleteEvent)
{
Player player = (Player) event.getSourceController();
Component video = player.getVisualComponent();
showPreview(videoContainer, video, player);
player.start();
}
}
/**
* Creates the ui controls for portaudio.
* @param portAudioPanel the panel
@ -439,47 +375,38 @@ else if (source == downButton)
* @throws MediaException a problem getting preview.
*/
private static void createPreview(CaptureDeviceInfo device,
final Container videoContainer)
final JComponent videoContainer)
throws IOException,
MediaException
{
videoContainer.removeAll();
if (videoPlayerInPreview != null)
disposePlayer(videoPlayerInPreview);
videoContainer.revalidate();
videoContainer.repaint();
if (device == null)
return;
DataSource dataSource = Manager.createDataSource(device.getLocator());
Dimension size = videoContainer.getPreferredSize();
/*
* Don't let the size be uselessly small just because the videoContainer
* has too small a preferred size.
*/
if ((size.width < 128) || (size.height < 96))
Iterator<MediaDevice> mDevsIter =
NeomediaActivator.getMediaServiceImpl()
.getDevices(MediaType.VIDEO, MediaUseCase.ANY)
.iterator();
while(mDevsIter.hasNext())
{
size.width = 128;
size.height = 96;
}
VideoMediaStreamImpl
.selectVideoSize(dataSource, size.width, size.height);
// A Player is documented to be created on a connected DataSource.
dataSource.connect();
Processor player = Manager.createProcessor(dataSource);
MediaDeviceImpl dev = (MediaDeviceImpl)mDevsIter.next();
if(dev.getCaptureDeviceInfo().equals(device))
{
Component c = (Component)NeomediaActivator.getMediaServiceImpl()
.getVideoPreviewComponent(
dev,
videoContainer.getSize().width,
videoContainer.getSize().height);
videoPlayerInPreview = player;
videoContainer.add(c);
player.addControllerListener(new ControllerListener()
{
public void controllerUpdate(ControllerEvent event)
{
controllerUpdateForPreview(event, videoContainer);
break;
}
});
player.configure();
}
}
/**
@ -490,7 +417,7 @@ public void controllerUpdate(ControllerEvent event)
*/
private static Component createPreview(int type, final JComboBox comboBox)
{
final Container preview;
final JComponent preview;
if (type == DeviceConfigurationComboBoxModel.VIDEO)
{
JLabel noPreview =
@ -523,7 +450,7 @@ public void actionPerformed(ActionEvent event)
Exception exception;
try
{
{
createPreview(device, preview);
exception = null;
}
@ -566,7 +493,21 @@ public void hierarchyChanged(HierarchyEvent event)
& HierarchyEvent.DISPLAYABILITY_CHANGED)
!= 0)
&& comboBox.isDisplayable())
comboBoxListener.actionPerformed(null);
{
// let current changes end their execution
// and after that trigger action on combobox
SwingUtilities.invokeLater(new Runnable(){
public void run()
{
comboBoxListener.actionPerformed(null);
}
});
}
else
{
if(!comboBox.isDisplayable())
videoDeviceInPreview = null;
}
}
});
} else
@ -580,26 +521,11 @@ public void hierarchyChanged(HierarchyEvent event)
* @param noVideoComponent the container component.
* @return the video container.
*/
private static Container createVideoContainer(Component noVideoComponent)
private static JComponent createVideoContainer(Component noVideoComponent)
{
return new VideoContainer(noVideoComponent);
}
/**
* Dispose the player used for the preview.
* @param player the player.
*/
private static void disposePlayer(Player player)
{
player.stop();
player.deallocate();
player.close();
if ((videoPlayerInPreview != null)
&& videoPlayerInPreview.equals(player))
videoPlayerInPreview = null;
}
/**
* The mnemonic for a type.
* @param type audio or video type.
@ -661,101 +587,4 @@ private static void move(JTable table, boolean up)
.getSelectedRow(), up);
table.getSelectionModel().setSelectionInterval(index, index);
}
/**
* Shows the preview panel.
* @param previewContainer the container
* @param preview the preview component.
* @param player the player.
*/
private static void showPreview(final Container previewContainer,
final Component preview, final Player player)
{
if (!SwingUtilities.isEventDispatchThread())
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
showPreview(previewContainer, preview, player);
}
});
return;
}
previewContainer.removeAll();
if (preview != null)
{
HierarchyListener hierarchyListener = new HierarchyListener()
{
private Window window;
private WindowListener windowListener;
public void dispose()
{
if (windowListener != null)
{
if (window != null)
{
window.removeWindowListener(windowListener);
window = null;
}
windowListener = null;
}
preview.removeHierarchyListener(this);
disposePlayer(player);
videoDeviceInPreview = null;
/*
* We've just disposed the player which created the preview
* component so the preview component is of no use
* regardless of whether the Media configuration form will
* be redisplayed or not. And since the preview component
* appears to be a huge object even after its player is
* disposed, make sure to not reference it.
*/
previewContainer.remove(preview);
}
public void hierarchyChanged(HierarchyEvent event)
{
if ((event.getChangeFlags()
& HierarchyEvent.DISPLAYABILITY_CHANGED)
== 0)
return;
if (!preview.isDisplayable())
{
dispose();
return;
}
if (windowListener == null)
{
window = SwingUtilities.windowForComponent(preview);
if (window != null)
{
windowListener = new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent event)
{
dispose();
}
};
window.addWindowListener(windowListener);
}
}
}
};
preview.addHierarchyListener(hierarchyListener);
previewContainer.add(preview);
}
else
disposePlayer(player);
}
}

@ -6,16 +6,25 @@
*/
package net.java.sip.communicator.impl.neomedia;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.media.*;
import javax.media.control.*;
import javax.media.protocol.*;
import javax.swing.*;
import net.java.sip.communicator.impl.neomedia.codec.*;
import net.java.sip.communicator.impl.neomedia.codec.video.*;
import net.java.sip.communicator.impl.neomedia.device.*;
import net.java.sip.communicator.impl.neomedia.format.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.neomedia.device.*;
import net.java.sip.communicator.service.neomedia.format.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
/**
* Implements <tt>MediaService</tt> for JMF.
@ -26,6 +35,11 @@
public class MediaServiceImpl
implements MediaService
{
/**
* The logger.
*/
private static final Logger logger
= Logger.getLogger(MediaServiceImpl.class);
/**
* With this property video support can be disabled (enabled by default).
@ -608,4 +622,246 @@ public Map<MediaFormat, Byte> getDynamicPayloadTypePreferences()
}
return dynamicPayloadTypePreferences;
}
/**
* Creates a preview component for the specified device(video device) used
* to show video preview from that device.
*
* @param device the video device
* @param preferredWidth the width we prefer for the component
* @param preferredHeight the height we prefer for the component
* @return the preview component.
*/
public Object getVideoPreviewComponent(MediaDevice device
, int preferredWidth, int preferredHeight)
{
JLabel noPreview =
new JLabel(NeomediaActivator.getResources().getI18NString(
"impl.media.configform.NO_PREVIEW"));
noPreview.setHorizontalAlignment(SwingConstants.CENTER);
noPreview.setVerticalAlignment(SwingConstants.CENTER);
final JComponent videoContainer
= new VideoContainer(noPreview);
videoContainer.setPreferredSize(
new Dimension(preferredWidth, preferredHeight));
videoContainer.setMaximumSize(
new Dimension(preferredWidth, preferredHeight));
try
{
if (device == null ||
((MediaDeviceImpl)device).getCaptureDeviceInfo() == null)
{
return videoContainer;
}
DataSource dataSource = Manager.createDataSource(
((MediaDeviceImpl)device).getCaptureDeviceInfo().getLocator());
/*
* Don't let the size be uselessly small just because the videoContainer
* has too small a preferred size.
*/
if ((preferredWidth < 128) || (preferredHeight < 96))
{
preferredHeight = 128;
preferredWidth = 96;
}
VideoMediaStreamImpl
.selectVideoSize(dataSource, preferredWidth, preferredHeight);
// A Player is documented to be created on a connected DataSource.
dataSource.connect();
Processor player = Manager.createProcessor(dataSource);
player.addControllerListener(new ControllerListener()
{
public void controllerUpdate(ControllerEvent event)
{
controllerUpdateForPreview(event, videoContainer);
}
});
player.configure();
return videoContainer;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
/**
* Listens and shows the video in the video container when needed.
* @param event the event when player has ready visual component.
* @param videoContainer the container.
*/
private static void controllerUpdateForPreview(ControllerEvent event,
JComponent videoContainer)
{
if (event instanceof ConfigureCompleteEvent)
{
Processor player = (Processor) event.getSourceController();
/*
* Use SwScaler for the scaling since it produces an image with
* better quality.
*/
TrackControl[] trackControls = player.getTrackControls();
if ((trackControls != null) && (trackControls.length != 0))
try
{
for (TrackControl trackControl : trackControls)
{
trackControl.setCodecChain(
new Codec[] { new SwScaler() });
break;
}
}
catch (UnsupportedPlugInException upiex)
{
logger.warn("Failed to add SwScaler to codec chain", upiex);
}
// Turn the Processor into a Player.
try
{
player.setContentDescriptor(null);
}
catch (NotConfiguredError nce)
{
logger.error(
"Failed to set ContentDescriptor of Processor",
nce);
}
player.realize();
}
else if (event instanceof RealizeCompleteEvent)
{
Player player = (Player) event.getSourceController();
Component video = player.getVisualComponent();
showPreview(videoContainer, video, player);
}
}
/**
* Shows the preview panel.
* @param previewContainer the container
* @param preview the preview component.
* @param player the player.
*/
private static void showPreview(final JComponent previewContainer,
final Component preview, final Player player)
{
if (!SwingUtilities.isEventDispatchThread())
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
showPreview(previewContainer, preview, player);
}
});
return;
}
previewContainer.removeAll();
if (preview != null)
{
HierarchyListener hierarchyListener = new HierarchyListener()
{
private Window window;
private WindowListener windowListener;
public void dispose()
{
if (windowListener != null)
{
if (window != null)
{
window.removeWindowListener(windowListener);
window = null;
}
windowListener = null;
}
preview.removeHierarchyListener(this);
disposePlayer(player);
/*
* We've just disposed the player which created the preview
* component so the preview component is of no use
* regardless of whether the Media configuration form will
* be redisplayed or not. And since the preview component
* appears to be a huge object even after its player is
* disposed, make sure to not reference it.
*/
previewContainer.remove(preview);
}
public void hierarchyChanged(HierarchyEvent event)
{
if ((event.getChangeFlags()
& HierarchyEvent.DISPLAYABILITY_CHANGED)
== 0)
return;
if (!preview.isDisplayable())
{
dispose();
return;
}
else
{
player.start();
}
if (windowListener == null)
{
window = SwingUtilities.windowForComponent(preview);
if (window != null)
{
windowListener = new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent event)
{
dispose();
}
};
window.addWindowListener(windowListener);
}
}
}
};
preview.addHierarchyListener(hierarchyListener);
previewContainer.add(preview);
previewContainer.revalidate();
previewContainer.repaint();
}
else
disposePlayer(player);
}
/**
* Dispose the player used for the preview.
* @param player the player.
*/
private static void disposePlayer(Player player)
{
player.stop();
player.deallocate();
player.close();
}
}

@ -34,7 +34,7 @@ public class OperationSetServerStoredAccountInfoMsnImpl
Logger.getLogger(OperationSetServerStoredAccountInfoMsnImpl.class);
/**
* The jabber provider that created us.
* The msn provider that created us.
*/
private ProtocolProviderServiceMsnImpl msnProvider = null;
/**
@ -499,14 +499,14 @@ private void assertConnected()
if (msnProvider == null)
{
throw new IllegalStateException(
"The jabber provider must be non-null and signed on "
"The msn provider must be non-null and signed on "
+ "before being able to communicate.");
}
if (!msnProvider.isRegistered())
{
throw new IllegalStateException(
"The jabber provider must be signed on before "
"The msn provider must be signed on before "
+ "being able to communicate.");
}
}

@ -6,7 +6,9 @@
*/
package net.java.sip.communicator.service.neomedia;
import java.awt.*;
import java.util.*;
import java.util.List;
import net.java.sip.communicator.service.neomedia.device.*;
import net.java.sip.communicator.service.neomedia.format.*;
@ -178,4 +180,16 @@ public MediaStream createMediaStream(StreamConnector connector,
* payload type number.
*/
public Map<MediaFormat, Byte> getDynamicPayloadTypePreferences();
/**
* Creates a preview component for the specified device(video device) used
* to show video preview from it.
*
* @param device the video device
* @param preferredWidth the width we prefer for the component
* @param preferredHeight the height we prefer for the component
* @return the preview component.
*/
public Object getVideoPreviewComponent(
MediaDevice device, int preferredWidth, int preferredHeight);
}

Loading…
Cancel
Save