- Add new scaler that uses libswscale and can change format (i.e. RGB to YUV, ...) and scale in one pass;

- Add the possibility to change output video size of a stream in VideoMediaDeviceSession;
- Add recompiled ffmpeg JNI for all supported platforms.
cusax-fix
Sebastien Vincent 16 years ago
parent f866c3b513
commit c65a383050

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -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)

@ -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

@ -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)
{

@ -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();
}
}

@ -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;
}
}

@ -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 <tt>Format</tt> to set to <tt>processor</tt>
*/
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);
/*

@ -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 <tt>VideoMediaDeviceSession</tt> instance which is to
* represent the work of a <tt>MediaStream</tt> with a specific video
@ -147,6 +158,31 @@ protected DataSource createCaptureDevice()
return captureDevice;
}
/**
* Sets the JMF <tt>Format</tt> in which a specific <tt>Processor</tt> is to
* output media data.
*
* @param processor the <tt>Processor</tt> to set the output <tt>Format</tt>
* of
* @param format the JMF <tt>Format</tt> to set to <tt>processor</tt>
*/
@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 <tt>MediaDevice</tt> is acceptable to be set as
* the <tt>MediaDevice</tt> of this instance. Makes sure that its

@ -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
*/

Loading…
Cancel
Save