aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip/communicator
diff options
context:
space:
mode:
authorLyubomir Marinov <lyubomir.marinov@jitsi.org>2011-06-17 09:49:15 +0000
committerLyubomir Marinov <lyubomir.marinov@jitsi.org>2011-06-17 09:49:15 +0000
commit88bab9eb924413f995f4f4a0d55fa45b92929d65 (patch)
treeb787b54d51e86df765c9eb39a9575ca6cd905dc9 /src/net/java/sip/communicator
parent7393c6829fe3461b4df35fea5a174de2407945db (diff)
downloadjitsi-88bab9eb924413f995f4f4a0d55fa45b92929d65.zip
jitsi-88bab9eb924413f995f4f4a0d55fa45b92929d65.tar.gz
jitsi-88bab9eb924413f995f4f4a0d55fa45b92929d65.tar.bz2
Introduces an H.264 configuration form to allow the selection of the default encoding profile and the preferred method to request key frames from the remote peers. Rebuilds the JNI FFmpeg library on Mac OS X to support the selections in question.
Diffstat (limited to 'src/net/java/sip/communicator')
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java32
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java9
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/codec/video/h264/ConfigurationPanel.java230
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/codec/video/h264/JNIEncoder.java46
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java7
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf1
-rw-r--r--src/net/java/sip/communicator/service/neomedia/control/KeyFrameControl.java28
7 files changed, 336 insertions, 17 deletions
diff --git a/src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java b/src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java
index 4339244..c29a415 100644
--- a/src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java
+++ b/src/net/java/sip/communicator/impl/neomedia/NeomediaActivator.java
@@ -129,9 +129,8 @@ public class NeomediaActivator
mediaProps.put( ConfigurationForm.FORM_TYPE,
ConfigurationForm.GENERAL_TYPE);
- // AudioConfigurationForm
- bundleContext
- .registerService(
+ // Audio
+ bundleContext.registerService(
ConfigurationForm.class.getName(),
new LazyConfigurationForm(
"net.java.sip.communicator.impl.neomedia"
@@ -142,9 +141,8 @@ public class NeomediaActivator
3),
mediaProps);
- // VideoConfigurationForm
- bundleContext
- .registerService(
+ // Video
+ bundleContext.registerService(
ConfigurationForm.class.getName(),
new LazyConfigurationForm(
"net.java.sip.communicator.impl.neomedia"
@@ -154,14 +152,30 @@ public class NeomediaActivator
"impl.neomedia.configform.VIDEO",
4),
mediaProps);
+ // H.264
+ Dictionary<String, String> h264Props
+ = new Hashtable<String, String>();
+ h264Props.put(
+ ConfigurationForm.FORM_TYPE,
+ ConfigurationForm.ADVANCED_TYPE);
+ bundleContext.registerService(
+ ConfigurationForm.class.getName(),
+ new LazyConfigurationForm(
+ "net.java.sip.communicator.impl.neomedia"
+ + ".codec.video.h264.ConfigurationPanel",
+ getClass().getClassLoader(),
+ "plugin.mediaconfig.VIDEO_ICON",
+ "impl.neomedia.configform.H264",
+ -1,
+ true),
+ h264Props);
- // ZRTPConfiguration panel
+ // ZRTP
Dictionary<String, String> securityProps
= new Hashtable<String, String>();
securityProps.put( ConfigurationForm.FORM_TYPE,
ConfigurationForm.SECURITY_TYPE);
- bundleContext
- .registerService(
+ bundleContext.registerService(
ConfigurationForm.class.getName(),
new LazyConfigurationForm(
"net.java.sip.communicator.impl.neomedia.ZrtpConfigurePanel",
diff --git a/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java b/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java
index b6526ee..2ed2129 100644
--- a/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java
+++ b/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java
@@ -57,13 +57,12 @@ public class VideoMediaStreamImpl
* The indicator which determines whether RTCP feedback Picture Loss
* Indication messages are to be used.
*/
- private boolean usePLI = false;
+ private boolean usePLI = true;
/**
* The <tt>KeyFrameControl</tt> of this <tt>VideoMediaStream</tt>.
*/
- private final KeyFrameControlImpl keyFrameControl
- = new KeyFrameControlImpl();
+ private KeyFrameControlImpl keyFrameControl;
/**
* The <tt>QualityControl</tt> of this <tt>VideoMediaStream</tt>.
@@ -451,7 +450,7 @@ public class VideoMediaStreamImpl
* VideoMediaStreamImpl so the key frame-related logic will be
* controlled by the keyFrameControl of this VideoMediaStreamImpl.
*/
- newVideoMediaDeviceSession.setKeyFrameControl(keyFrameControl);
+ newVideoMediaDeviceSession.setKeyFrameControl(getKeyFrameControl());
}
}
@@ -852,6 +851,8 @@ public class VideoMediaStreamImpl
*/
public KeyFrameControl getKeyFrameControl()
{
+ if (keyFrameControl == null)
+ keyFrameControl = new KeyFrameControlImpl();
return keyFrameControl;
}
diff --git a/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/ConfigurationPanel.java b/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/ConfigurationPanel.java
new file mode 100644
index 0000000..aeb4b26
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/ConfigurationPanel.java
@@ -0,0 +1,230 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.neomedia.codec.video.h264;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.impl.neomedia.*;
+import net.java.sip.communicator.service.configuration.*;
+import net.java.sip.communicator.service.neomedia.control.*;
+import net.java.sip.communicator.service.resources.*;
+import net.java.sip.communicator.util.swing.*;
+
+/**
+ * Implements the H.264 configuration form (panel).
+ *
+ * @author Lyubomir Marinov
+ */
+public class ConfigurationPanel
+ extends TransparentPanel
+{
+ /**
+ * Initializer a new <tt>ConfigurationPanel</tt> instance.
+ */
+ public ConfigurationPanel()
+ {
+ /* Create the UI components. */
+ super(new FlowLayout());
+
+ TransparentPanel contentPanel
+ = new TransparentPanel(new GridBagLayout());
+ add(contentPanel);
+
+ ResourceManagementService resources = NeomediaActivator.getResources();
+ GridBagConstraints gridBagConstraints = new GridBagConstraints();
+
+ JLabel defaultProfileLabel
+ = new JLabel(
+ resources.getI18NString(
+ "impl.neomedia.configform.H264.defaultProfile"));
+ gridBagConstraints.anchor = GridBagConstraints.LINE_START;
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 0;
+ contentPanel.add(defaultProfileLabel, gridBagConstraints);
+
+ JComboBox defaultProfileComboBox = new JComboBox();
+ defaultProfileComboBox.setEditable(false);
+ defaultProfileComboBox.addItem(
+ new NameValuePair(
+ resources.getI18NString(
+ "impl.neomedia.configform.H264.defaultProfile."
+ + JNIEncoder.BASELINE_PROFILE),
+ JNIEncoder.BASELINE_PROFILE));
+ defaultProfileComboBox.addItem(
+ new NameValuePair(
+ resources.getI18NString(
+ "impl.neomedia.configform.H264.defaultProfile."
+ + JNIEncoder.MAIN_PROFILE),
+ JNIEncoder.MAIN_PROFILE));
+ gridBagConstraints.anchor = GridBagConstraints.LINE_START;
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 0;
+ contentPanel.add(defaultProfileComboBox, gridBagConstraints);
+
+ JLabel preferredKeyFrameRequesterLabel
+ = new JLabel(
+ resources.getI18NString(
+ "impl.neomedia.configform.H264"
+ + ".preferredKeyFrameRequester"));
+ gridBagConstraints.anchor = GridBagConstraints.LINE_START;
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 1;
+ contentPanel.add(preferredKeyFrameRequesterLabel, gridBagConstraints);
+
+ JComboBox preferredKeyFrameRequesterComboBox = new JComboBox();
+ preferredKeyFrameRequesterComboBox.setEditable(false);
+ preferredKeyFrameRequesterComboBox.addItem(
+ new NameValuePair(
+ resources.getI18NString(
+ "impl.neomedia.configform.H264"
+ + ".preferredKeyFrameRequester."
+ + KeyFrameControl.KeyFrameRequester.RTCP),
+ KeyFrameControl.KeyFrameRequester.RTCP));
+ preferredKeyFrameRequesterComboBox.addItem(
+ new NameValuePair(
+ resources.getI18NString(
+ "impl.neomedia.configform.H264"
+ + ".preferredKeyFrameRequester."
+ + KeyFrameControl.KeyFrameRequester.SIGNALING),
+ KeyFrameControl.KeyFrameRequester.SIGNALING));
+ gridBagConstraints.anchor = GridBagConstraints.LINE_START;
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 1;
+ contentPanel.add(
+ preferredKeyFrameRequesterComboBox,
+ gridBagConstraints);
+
+ /*
+ * Load the values from the ConfigurationService into the UI components.
+ */
+ ConfigurationService configuration
+ = NeomediaActivator.getConfigurationService();
+
+ setSelectedNameValuePair(
+ defaultProfileComboBox,
+ configuration.getString(
+ JNIEncoder.DEFAULT_PROFILE_PNAME,
+ JNIEncoder.DEFAULT_DEFAULT_PROFILE));
+ addActionListener(
+ defaultProfileComboBox,
+ JNIEncoder.DEFAULT_PROFILE_PNAME);
+
+ setSelectedNameValuePair(
+ preferredKeyFrameRequesterComboBox,
+ configuration.getString(
+ KeyFrameControl.KeyFrameRequester.PREFERRED_PNAME,
+ KeyFrameControl.KeyFrameRequester.DEFAULT_PREFERRED));
+ addActionListener(
+ preferredKeyFrameRequesterComboBox,
+ KeyFrameControl.KeyFrameRequester.PREFERRED_PNAME);
+ }
+
+ /**
+ * Adds an <tt>ActionListener</tt> to a specific <tt>JComboBox</tt>
+ * populated with <tt>NameValuePair</tt>s which sets the value of a specific
+ * <tt>ConfigurationService</tt> property to the <tt>value</tt> of the
+ * selected <tt>NameValuePair</tt> of the <tt>comboBox</tt>.
+ *
+ * @param comboBox the <tt>JComboBox</tt> to add an <tt>ActionListener</tt>
+ * to
+ * @param property the name of the <tt>ConfigurationService</tt> property
+ * to set the value of
+ */
+ private void addActionListener(
+ final JComboBox comboBox,
+ final String property)
+ {
+ comboBox.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ NameValuePair nameValuePair
+ = (NameValuePair) comboBox.getSelectedItem();
+
+ if (nameValuePair != null)
+ {
+ NeomediaActivator.getConfigurationService()
+ .setProperty(property, nameValuePair.value);
+ }
+ }
+ });
+ }
+
+ /**
+ * Sets the selected item in a specific <tt>JComboBox</tt> populated with
+ * <tt>NameValuePair</tt>s to the one which has a specific <tt>value</tt>.
+ *
+ * @param comboBox the <tt>JComboBox</tt> to set the selected item of
+ * @param value the value of the <tt>NameValuePair</tt> to set as the
+ * selected item of <tt>comboBox</tt>
+ */
+ private void setSelectedNameValuePair(JComboBox comboBox, String value)
+ {
+ int itemCount = comboBox.getItemCount();
+
+ for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
+ {
+ NameValuePair nameValuePair
+ = (NameValuePair) comboBox.getItemAt(itemIndex);
+
+ if (nameValuePair.value.equals(value))
+ {
+ comboBox.setSelectedIndex(itemIndex);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Represents a <tt>String</tt> value which has a human-readable name
+ * associated with it for display purposes.
+ */
+ private static class NameValuePair
+ {
+ /**
+ * The human-readable name of this <tt>NameValuePair</tt>.
+ */
+ public final String name;
+
+ /**
+ * The <tt>String</tt> value represented by this <tt>NameValuePair</tt>.
+ */
+ public final String value;
+
+ /**
+ * Initializes a new <tt>NameValuePair</tt> which is to represent a
+ * specific <tt>String</tt> <tt>value</tt> which is to be displayed to
+ * the user as <tt>name</tt>.
+ *
+ * @param name the human-readable name of the new instance
+ * @param value the <tt>String</tt> value to be represented by the new
+ * instance
+ */
+ public NameValuePair(String name, String value)
+ {
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * Returns a human-readable representation of this <tt>Object</tt> i.e.
+ * the name of this <tt>NameValuePair</tt>.
+ *
+ * @return a human-readable representation of this <tt>Object</tt> i.e.
+ * the name of this <tt>NameValuePair</tt>
+ */
+ @Override
+ public String toString()
+ {
+ return name;
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/JNIEncoder.java b/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/JNIEncoder.java
index e67c791..bb894f4 100644
--- a/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/JNIEncoder.java
+++ b/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/JNIEncoder.java
@@ -12,8 +12,10 @@ import java.util.*;
import javax.media.*;
import javax.media.format.*;
+import net.java.sip.communicator.impl.neomedia.*;
import net.java.sip.communicator.impl.neomedia.codec.*;
import net.java.sip.communicator.impl.neomedia.format.*;
+import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.neomedia.event.*;
import net.java.sip.communicator.util.*;
import net.sf.fmj.media.*;
@@ -36,17 +38,45 @@ public class JNIEncoder
private static final Logger logger = Logger.getLogger(JNIEncoder.class);
/**
+ * The name of the baseline H.264 (encoding) profile.
+ */
+ public static final String BASELINE_PROFILE = "baseline";
+
+ /**
* The frame rate to be assumed by <tt>JNIEncoder</tt> instance in the
* absence of any other frame rate indication.
*/
static final int DEFAULT_FRAME_RATE = 15;
/**
+ * The name of the <tt>ConfigurationService</tt> property which specifies
+ * the H.264 (encoding) profile to be used in the absence of negotiation.
+ * Though it seems that RFC 3984 "RTP Payload Format for H.264 Video"
+ * specifies the baseline profile as the default, we have till the time of
+ * this writing defaulted to the main profile and we do not currently want
+ * to change from the main to the base profile unless we really have to.
+ */
+ public static final String DEFAULT_PROFILE_PNAME
+ = "net.java.sip.communicator.service.media.codec.video.h264."
+ + "defaultProfile";
+
+ /**
* Key frame every 150 frames.
*/
static final int IFRAME_INTERVAL = 150;
/**
+ * The name of the main H.264 (encoding) profile.
+ */
+ public static final String MAIN_PROFILE = "main";
+
+ /**
+ * The default value of the {@link #DEFAULT_PROFILE_PNAME}
+ * <tt>ConfigurationService</tt> property.
+ */
+ public static final String DEFAULT_DEFAULT_PROFILE = MAIN_PROFILE;
+
+ /**
* The name of the format parameter which specifies the packetization mode
* of H.264 RTP payload.
*/
@@ -361,13 +391,23 @@ public class JNIEncoder
/*
* XXX We do not currently negotiate the profile so, regardless of the
- * many AVCodecContext properties we have set above, force the baseline
- * profile which is the default in the absence of negotiation.
+ * many AVCodecContext properties we have set above, force the default
+ * profile configuration.
*/
+ ConfigurationService configuration
+ = NeomediaActivator.getConfigurationService();
+ String profile
+ = (configuration == null)
+ ? null
+ : configuration.getString(
+ DEFAULT_PROFILE_PNAME,
+ DEFAULT_DEFAULT_PROFILE);
try
{
FFmpeg.avcodeccontext_set_profile(avctx,
- FFmpeg.FF_PROFILE_H264_BASELINE);
+ BASELINE_PROFILE.equalsIgnoreCase(profile)
+ ? FFmpeg.FF_PROFILE_H264_BASELINE
+ : FFmpeg.FF_PROFILE_H264_MAIN);
}
catch (UnsatisfiedLinkError ule)
{
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java
index 8743ba7..e55b9cf 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java
@@ -18,6 +18,7 @@ import javax.sip.header.*;
import javax.sip.message.*;
import net.java.sip.communicator.impl.protocol.sip.sdp.*;
+import net.java.sip.communicator.service.neomedia.control.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.Contact;
import net.java.sip.communicator.service.protocol.event.*;
@@ -97,7 +98,11 @@ public class CallPeerSipImpl
* <tt>picture_fast_update</tt> to this remote peer (as part of the
* execution of {@link #requestKeyFrame()}).
*/
- private boolean sendPictureFastUpdate = false;
+ private boolean sendPictureFastUpdate
+ = KeyFrameControl.KeyFrameRequester.SIGNALING.equals(
+ SipActivator.getConfigurationService().getString(
+ KeyFrameControl.KeyFrameRequester.PREFERRED_PNAME,
+ KeyFrameControl.KeyFrameRequester.DEFAULT_PREFERRED));
/**
* Creates a new call peer with address <tt>peerAddress</tt>.
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
index e445a9e..aff5a65 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
+++ b/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
@@ -40,6 +40,7 @@ Import-Package: org.apache.log4j,
net.java.sip.communicator.service.certificate,
net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.neomedia,
+ net.java.sip.communicator.service.neomedia.control,
net.java.sip.communicator.service.neomedia.device,
net.java.sip.communicator.service.neomedia.event,
net.java.sip.communicator.service.neomedia.format,
diff --git a/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControl.java b/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControl.java
index 9f16bce..7da13ba 100644
--- a/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControl.java
+++ b/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControl.java
@@ -62,6 +62,34 @@ public interface KeyFrameControl
public interface KeyFrameRequester
{
/**
+ * The name of the <tt>ConfigurationService</tt> property which
+ * specifies the preferred <tt>KeyFrameRequester</tt> to be used.
+ */
+ public static final String PREFERRED_PNAME
+ = "net.java.sip.communicator.service.media.codec.video.h264."
+ + "preferredKeyFrameRequester";
+
+ /**
+ * The value of the {@link #PREFERRED_PNAME}
+ * <tt>ConfigurationService</tt> property which indicates that the
+ * RTCP <tt>KeyFrameRequester</tt> is preferred.
+ */
+ public static final String RTCP = "rtcp";
+
+ /**
+ * The value of the {@link #PREFERRED_PNAME}
+ * <tt>ConfigurationService</tt> property which indicates that the
+ * signaling/protocol <tt>KeyFrameRequester</tt> is preferred.
+ */
+ public static final String SIGNALING = "signaling";
+
+ /**
+ * The default value of the {@link #PREFERRED_PNAME}
+ * <tt>ConfigurationService</tt> property.
+ */
+ public static final String DEFAULT_PREFERRED = RTCP;
+
+ /**
* Requests a key frame from the remote peer of the associated
* <tt>VideoMediaStream</tt>.
*