diff --git a/lib/native/freebsd-64/libffmpeg.so b/lib/native/freebsd-64/libffmpeg.so
index 579209272..077ddb5cb 100755
Binary files a/lib/native/freebsd-64/libffmpeg.so and b/lib/native/freebsd-64/libffmpeg.so differ
diff --git a/lib/native/freebsd/libffmpeg.so b/lib/native/freebsd/libffmpeg.so
index c080267be..8610d8059 100755
Binary files a/lib/native/freebsd/libffmpeg.so and b/lib/native/freebsd/libffmpeg.so differ
diff --git a/lib/native/linux-64/libffmpeg.so b/lib/native/linux-64/libffmpeg.so
index 42096a668..1b9b5c049 100755
Binary files a/lib/native/linux-64/libffmpeg.so and b/lib/native/linux-64/libffmpeg.so differ
diff --git a/lib/native/linux/libffmpeg.so b/lib/native/linux/libffmpeg.so
index 0622ab4d0..90b7cd8aa 100755
Binary files a/lib/native/linux/libffmpeg.so and b/lib/native/linux/libffmpeg.so differ
diff --git a/lib/native/mac/libffmpeg.jnilib b/lib/native/mac/libffmpeg.jnilib
index 17d8d444a..569a55c3f 100755
Binary files a/lib/native/mac/libffmpeg.jnilib and b/lib/native/mac/libffmpeg.jnilib differ
diff --git a/lib/native/windows-64/ffmpeg.dll b/lib/native/windows-64/ffmpeg.dll
index fa3f2a23f..8ffac89e8 100644
Binary files a/lib/native/windows-64/ffmpeg.dll and b/lib/native/windows-64/ffmpeg.dll differ
diff --git a/lib/native/windows/ffmpeg.dll b/lib/native/windows/ffmpeg.dll
index 9fddfca4b..276aa59c9 100644
Binary files a/lib/native/windows/ffmpeg.dll and b/lib/native/windows/ffmpeg.dll differ
diff --git a/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG.c b/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG.c
index ec434a565..515a7a036 100644
--- a/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG.c
+++ b/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG.c
@@ -438,15 +438,15 @@ Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_avpicture_1get_1
static int image_convert(
AVPicture* dst, int dst_pix_fmt,
-const AVPicture* src, int pix_fmt, int width, int height)
+const AVPicture* src, int pix_fmt, int width, int height, jint newWidth, jint newHeight)
{
struct SwsContext *img_convert_ctx =
sws_getContext(
width, height, pix_fmt,
- width, height, dst_pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
+ newWidth, newHeight, dst_pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
int result = sws_scale(img_convert_ctx,
- src->data, src->linesize, 0, height,
+ (uint8_t**)src->data, (int*)src->linesize, 0, height,
dst->data, dst->linesize);
sws_freeContext(img_convert_ctx);
@@ -454,7 +454,7 @@ const AVPicture* src, int pix_fmt, int width, int height)
}
JNIEXPORT jint JNICALL
-Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_img_1convert (
+Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_img_1convert__JIJIII (
JNIEnv *jniEnv, jclass clazz, jlong dst, jint dst_pix_fmt, jlong src,
jint pix_fmt, jint width, jint height)
{
@@ -465,9 +465,50 @@ Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_img_1convert (
(const AVPicture *) src,
(int) pix_fmt,
(int) width,
+ (int) height,
+ (int) width,
(int) height);
}
+JNIEXPORT jint JNICALL
+Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_img_1convert___3BI_3BIIIII
+ (JNIEnv *jniEnv, jclass clazz, jbyteArray dst, jint dst_pix_fmt,
+ jbyteArray src, jint pix_fmt, jint width, jint height, jint newWidth, jint newHeight)
+{
+ AVPicture dst_dummy;
+ AVPicture src_dummy;
+ int size = width * height;
+ jint ret = 0;
+/*
+ uint8_t* dst_buf = (*jniEnv)->GetPrimitiveArrayCritical(jniEnv, dst, 0);
+ uint8_t* src_buf = (*jniEnv)->GetPrimitiveArrayCritical(jniEnv, src, 0);
+*/
+ uint8_t* dst_buf = (*jniEnv)->GetByteArrayElements(jniEnv, dst, 0);
+ uint8_t* src_buf = (*jniEnv)->GetByteArrayElements(jniEnv, src, 0);
+
+ if(!src || !dst)
+ {
+ return -1;
+ }
+
+ /* assign AVPicture with buffer */
+ avpicture_fill(&dst_dummy, dst_buf, (int)dst_pix_fmt, newWidth, newHeight);
+ avpicture_fill(&src_dummy, src_buf, (int)pix_fmt, width, height);
+
+ ret = image_convert(&dst_dummy, (int)dst_pix_fmt, &src_dummy, (int)pix_fmt,
+ (int)width, (int)height, (int)newWidth, (int)newHeight);
+
+ /* release pointers */
+/*
+ (*jniEnv)->ReleasePrimitiveArrayCritical(jniEnv, dst, dst_buf, 0);
+ (*jniEnv)->ReleasePrimitiveArrayCritical(jniEnv, src, src_buf, 0);
+*/
+ (*jniEnv)->ReleaseByteArrayElements(jniEnv, dst, dst_buf, 0);
+ (*jniEnv)->ReleaseByteArrayElements(jniEnv, src, src_buf, 0);
+ return ret;
+}
+
+
JNIEXPORT void JNICALL
Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_memcpy___3IIIJ (
JNIEnv *jniEnv, jclass clazz, jintArray dst, jint dst_offset,
@@ -491,6 +532,13 @@ Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_getRGB32Format
return PIX_FMT_RGB32;
}
+JNIEXPORT jint JNICALL
+Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_getRGBAFormat
+ (JNIEnv *env, jclass clazz)
+{
+ return PIX_FMT_RGBA;
+}
+
JNIEXPORT jint JNICALL
Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_getYUV420PFormat
(JNIEnv *env, jclass clazz)
diff --git a/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG.h b/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG.h
index 0e61df22e..d5825f176 100644
--- a/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG.h
+++ b/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG.h
@@ -29,6 +29,14 @@ extern "C" {
JNIEXPORT jint JNICALL Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_getRGB32Format
(JNIEnv *, jclass);
+/*
+ * Class: net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG
+ * Method: getRGBAFormat
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_getRGBAFormat
+ (JNIEnv *, jclass);
+
/*
* Class: net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG
* Method: getYUV420PFormat
@@ -458,9 +466,17 @@ JNIEXPORT jint JNICALL Java_net_java_sip_communicator_impl_neomedia_codec_video_
* Method: img_convert
* Signature: (JIJIII)I
*/
-JNIEXPORT jint JNICALL Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_img_1convert
+JNIEXPORT jint JNICALL Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_img_1convert__JIJIII
(JNIEnv *, jclass, jlong, jint, jlong, jint, jint, jint);
+/*
+ * Class: net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG
+ * Method: img_convert
+ * Signature: ([BI[BIIIII)I
+ */
+JNIEXPORT jint JNICALL Java_net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG_img_1convert___3BI_3BIIIII
+ (JNIEnv *, jclass, jbyteArray, jint, jbyteArray, jint, jint, jint, jint, jint);
+
/*
* Class: net_java_sip_communicator_impl_neomedia_codec_video_FFMPEG
* Method: memcpy
diff --git a/src/net/java/sip/communicator/impl/neomedia/codec/EncodingConfiguration.java b/src/net/java/sip/communicator/impl/neomedia/codec/EncodingConfiguration.java
index 0f2641359..ef87ec6c4 100644
--- a/src/net/java/sip/communicator/impl/neomedia/codec/EncodingConfiguration.java
+++ b/src/net/java/sip/communicator/impl/neomedia/codec/EncodingConfiguration.java
@@ -62,7 +62,8 @@ public class EncodingConfiguration
"net.java.sip.communicator.impl.neomedia.codec.video.h264.JNIEncoder",
"net.java.sip.communicator.impl.neomedia.codec.video.h264.Packetizer",
"net.java.sip.communicator.impl.neomedia.codec.video.h264.JNIDecoder",
- "net.java.sip.communicator.impl.neomedia.codec.video.ImageScaler",
+ //"net.java.sip.communicator.impl.neomedia.codec.video.ImageScaler",
+ "net.java.sip.communicator.impl.neomedia.codec.video.SwScaler",
"net.java.sip.communicator.impl.neomedia.codec.audio.speex.JavaEncoder",
"net.java.sip.communicator.impl.neomedia.codec.audio.speex.JavaDecoder",
"net.java.sip.communicator.impl.neomedia.codec.audio.ilbc.JavaEncoder",
@@ -328,6 +329,9 @@ public void registerCustomCodecs()
.getPlugInList(null, null, PlugInManager.CODEC));
boolean commit = false;
+ /* remove JavaRGBToYUV */
+ PlugInManager.removePlugIn("com.sun.media.codec.video.colorspace.JavaRGBToYUV", PlugInManager.CODEC);
+
for (String className : CUSTOM_CODECS)
{
diff --git a/src/net/java/sip/communicator/impl/neomedia/codec/video/FFMPEG.java b/src/net/java/sip/communicator/impl/neomedia/codec/video/FFMPEG.java
index 2551cc10b..27c702fbe 100644
--- a/src/net/java/sip/communicator/impl/neomedia/codec/video/FFMPEG.java
+++ b/src/net/java/sip/communicator/impl/neomedia/codec/video/FFMPEG.java
@@ -24,12 +24,16 @@ public class FFMPEG
public static final int FF_MB_DECISION_SIMPLE = 0;
public static final int PIX_FMT_RGB32;
+
+ public static final int PIX_FMT_RGBA;
public static final int PIX_FMT_YUV420P;
public static final int X264_RC_ABR = 2;
public static native int getRGB32Format();
+
+ public static native int getRGBAFormat();
public static native int getYUV420PFormat();
@@ -172,6 +176,10 @@ public static native int avpicture_get_size(int pix_fmt, int width,
public static native int img_convert(long dst, int dst_pix_fmt, long src,
int pix_fmt, int width, int height);
+
+ public static native int img_convert(byte dst[], int dst_pix_fmt,
+ byte src[], int pix_fmt, int width, int height, int newWidth,
+ int newHeight);
public static native void memcpy(int[] dst, int dst_offset, int dst_length,
long src);
@@ -185,7 +193,8 @@ public static native void memcpy(long dst, byte[] src, int src_offset,
av_register_all();
avcodec_init();
- PIX_FMT_RGB32 = getRGB32Format();
+ PIX_FMT_RGB32 = getRGB32Format(); /* for decoding */
+ PIX_FMT_RGBA = getRGBAFormat(); /* for encoding */
PIX_FMT_YUV420P = getYUV420PFormat();
}
}
diff --git a/src/net/java/sip/communicator/impl/neomedia/codec/video/SwScaler.java b/src/net/java/sip/communicator/impl/neomedia/codec/video/SwScaler.java
new file mode 100644
index 000000000..a8131df63
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/neomedia/codec/video/SwScaler.java
@@ -0,0 +1,196 @@
+/*
+ * SIP Communicator, 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;
+
+import java.awt.*;
+
+import javax.media.*;
+import javax.media.format.*;
+
+import net.sf.fmj.media.*;
+
+/**
+ * Codec that use libswccale to scale images from one size to
+ * another and change format (typically RGB to YUV).
+ *
+ * @author Sebastien Vincent
+ */
+public class SwScaler
+ extends AbstractCodec
+ implements Codec
+{
+
+ /**
+ * Supported input formats.
+ */
+ private final Format[] supportedInputFormats = new Format[] {
+ new RGBFormat(null, -1, Format.byteArray, -1.0f, 32, -1, -1, -1)
+ };
+
+ /**
+ * Supported output formats.
+ */
+ private Format[] supportedOutputFormats = new Format[] {
+ new YUVFormat(null, -1, Format.byteArray, -1.0f, YUVFormat.YUV_420, -1, -1, 0, -1, -1)
+ };
+
+ /**
+ * Set output size.
+ *
+ * @param size size to set
+ */
+ public void setOutputSize(Dimension size)
+ {
+ if(size == null)
+ {
+ size = new Dimension(640, 480);
+ }
+
+ Format newFormat = new YUVFormat(size, -1, Format.byteArray, -1.0f, YUVFormat.YUV_420, -1, -1, 0, -1, -1);
+ supportedOutputFormats[0] = newFormat;
+ }
+
+ /**
+ * Get the supported input formats.
+ *
+ * @return array of supported input format
+ */
+ @Override
+ public Format[] getSupportedInputFormats()
+ {
+ return supportedInputFormats;
+ }
+
+ /**
+ * Get the supported output formats for an input ones.
+ *
+ * @param input input format to convert
+ * @return array of supported output format
+ */
+ @Override
+ public Format[] getSupportedOutputFormats(Format input)
+ {
+ if(input == null)
+ {
+ return supportedOutputFormats;
+ }
+
+ //System.out.println("input: " + ((VideoFormat)input).getSize());
+ if(((VideoFormat)supportedOutputFormats[0]).getSize() != null)
+ {
+ return supportedOutputFormats;
+ }
+
+ return new Format[] { new YUVFormat(((VideoFormat)input).getSize(), -1, Format.byteArray, -1.0f, YUVFormat.YUV_420, -1, -1, 0, -1, -1)};
+ }
+
+ /**
+ * Set the input format.
+ *
+ * @param format format to set
+ * @return format
+ */
+ @Override
+ public Format setInputFormat(Format format)
+ {
+ //System.out.println("setInput: " + ((VideoFormat)format).getSize());
+ final VideoFormat videoFormat = (VideoFormat) format;
+
+ if (videoFormat.getSize() == null)
+ return null; // must set a size.
+
+ format = super.setInputFormat(format);
+ return format;
+ }
+
+ /**
+ * Set the output format.
+ *
+ * @param format format to set
+ * @return format
+ */
+ @Override
+ public Format setOutputFormat(Format format)
+ {
+ //System.out.println("setOutput: " + ((VideoFormat)format).getSize());
+ format = super.setOutputFormat(format);
+ return format;
+ }
+
+ /**
+ * Process (format convertion, rescale) a buffer.
+ *
+ * @param input input buffer
+ * @param output output buffer
+ * @return BUFFER_PROCESSED_OK if buffer successfully processed
+ */
+ @Override
+ public int process(Buffer input, Buffer output)
+ {
+ VideoFormat vinput = (VideoFormat)input.getFormat();
+ VideoFormat voutput = (VideoFormat)output.getFormat();
+ int inputWidth = (int)vinput.getSize().getWidth();
+ int inputHeight = (int)vinput.getSize().getHeight();
+ int outputWidth = (int)voutput.getSize().getWidth();
+ int outputHeight = (int)voutput.getSize().getHeight();
+ byte src[] = (byte[])input.getData();
+ byte dst[] = (byte[])output.getData();
+ int outputSize = 0;
+ int infmt = 0;
+ int outfmt = 0;
+
+ if (!checkInputBuffer(input))
+ {
+ return BUFFER_PROCESSED_FAILED;
+ }
+
+ if (isEOM(input))
+ {
+ propagateEOM(output); // TODO: what about data? can there be any?
+ return BUFFER_PROCESSED_OK;
+ }
+
+ /* determine output format and output size needed */
+ if(voutput instanceof YUVFormat)
+ {
+ /* YUV420P is 12 bpp (bit per pixel) => 1,5 bytes */
+ outputSize = (int)(outputWidth * outputHeight * 1.5);
+ outfmt = FFMPEG.PIX_FMT_YUV420P;
+ }
+ else /* RGB format */
+ {
+ outputSize = (outputWidth * outputHeight * 4);
+ outfmt = FFMPEG.PIX_FMT_RGBA;
+ }
+
+ /* determine input format */
+ if(vinput instanceof YUVFormat)
+ {
+ infmt = FFMPEG.PIX_FMT_YUV420P;
+ }
+ else /* RGBFormat */
+ {
+ infmt = FFMPEG.PIX_FMT_RGBA;
+ }
+
+ if(dst == null || dst.length < outputSize)
+ {
+ dst = new byte[outputSize];
+ }
+
+ /* convertion! */
+ //System.out.println("Convert: " + inputWidth + "x" + inputHeight + " to " + outputWidth + "x" + outputHeight);
+ FFMPEG.img_convert(dst, outfmt, src, infmt, inputWidth, inputHeight, outputWidth, outputHeight);
+
+ output.setData(dst);
+ output.setLength(dst.length);
+ output.setOffset(0);
+
+ return BUFFER_PROCESSED_OK;
+ }
+}
+
diff --git a/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java b/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java
index 78a19d0dd..decfcb025 100644
--- a/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java
+++ b/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java
@@ -19,6 +19,7 @@
import net.java.sip.communicator.impl.neomedia.*;
import net.java.sip.communicator.impl.neomedia.format.*;
import net.java.sip.communicator.impl.neomedia.protocol.*;
+import net.java.sip.communicator.impl.neomedia.codec.video.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.neomedia.device.*;
import net.java.sip.communicator.service.neomedia.format.*;
@@ -1226,7 +1227,7 @@ else if (processorIsPrematurelyClosed
* of
* @param format the JMF Format to set to processor
*/
- private void setFormat(Processor processor, Format format)
+ protected void setFormat(Processor processor, Format format)
{
TrackControl[] trackControls = processor.getTrackControls();
MediaType mediaType = getMediaType();
@@ -1276,7 +1277,36 @@ private void setFormat(Processor processor, Format format)
case VIDEO:
if (supportedFormats[0] instanceof VideoFormat)
{
- supportedFormat
+ VideoFormat tmp = (VideoFormat)format;
+ Dimension size = tmp.getSize();
+
+ if(size != null)
+ {
+ /* We have been explictely told to use
+ * a specified output size so create a
+ * custom SwScaler that will rescale and
+ * change format in one call
+ */
+ Codec ar[] = new Codec[1];
+ SwScaler scaler = new SwScaler();
+
+ scaler.setOutputSize(size);
+ ar[0] = scaler;
+
+ /* add our custom SwScaler to the codec chain so that
+ * it will be used instead of default SwScaler
+ */
+ try
+ {
+ trackControl.setCodecChain(ar);
+ }
+ catch(Exception e)
+ {
+ System.out.println("Error setCodecChain: " + e);
+ }
+ }
+
+ supportedFormat
= findFirstMatchingFormat(supportedFormats, format);
/*
diff --git a/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java b/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java
index de1341faf..9e735589a 100644
--- a/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java
+++ b/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java
@@ -9,6 +9,7 @@
import java.awt.*;
import javax.media.*;
+import javax.media.format.*;
import javax.media.control.*;
import javax.media.protocol.*;
@@ -47,6 +48,16 @@ public class VideoMediaDeviceSession
*/
private Player localPlayer = null;
+ /**
+ * Output size of the stream.
+ *
+ * It is used to specify a different size (generally lesser ones)
+ * than the capture device provides. Typically one usage can be
+ * in desktop streaming/sharing session when sender desktop is bigger
+ * than remote ones.
+ */
+ private Dimension outputSize = null;
+
/**
* Initializes a new VideoMediaDeviceSession instance which is to
* represent the work of a MediaStream with a specific video
@@ -147,6 +158,31 @@ protected DataSource createCaptureDevice()
return captureDevice;
}
+ /**
+ * Sets the JMF Format in which a specific Processor is to
+ * output media data.
+ *
+ * @param processor the Processor to set the output Format
+ * of
+ * @param format the JMF Format to set to processor
+ */
+ @Override
+ protected void setFormat(Processor processor, Format format)
+ {
+ Format newFormat = null;
+ VideoFormat tmp = (VideoFormat)format;
+
+ /* add a size in the output format, as VideoFormat has no
+ * set accessors, we recreate the object
+ */
+ if(outputSize != null)
+ {
+ newFormat = new VideoFormat(tmp.getEncoding(), outputSize, tmp.getMaxDataLength(), tmp.getDataType(), tmp.getFrameRate());
+ }
+
+ super.setFormat(processor, newFormat != null ? newFormat : format);
+ }
+
/**
* Asserts that a specific MediaDevice is acceptable to be set as
* the MediaDevice of this instance. Makes sure that its
diff --git a/src/net/java/sip/communicator/impl/neomedia/imgstreaming/NativeScreenCapture.java b/src/net/java/sip/communicator/impl/neomedia/imgstreaming/NativeScreenCapture.java
index 66f170ff9..82568e26b 100644
--- a/src/net/java/sip/communicator/impl/neomedia/imgstreaming/NativeScreenCapture.java
+++ b/src/net/java/sip/communicator/impl/neomedia/imgstreaming/NativeScreenCapture.java
@@ -9,9 +9,10 @@
import java.awt.image.*;
/**
- * This class uses native code to capture
- * desktop screen. It should work for Windows and
- * X11-based Unix such as Linux and FreeBSD.
+ * This class uses native code to capture desktop screen.
+ *
+ * It should work for Windows, Mac OS X and X11-based Unix such as Linux
+ * and FreeBSD.
*
* @author Sebastien Vincent
*/