Add H263+ video codec.

cusax-fix
Sebastien Vincent 16 years ago
parent c14ffbdffb
commit a5dadec391

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -51,6 +51,8 @@ patch -p0 < ffmpeg-23181.diff
--disable-network \
--enable-libx264 --enable-gpl --enable-parser=h264 --enable-encoder=libx264 \
--enable-decoder=h264 --enable-muxer=h264 --enable-demuxer=h264 \
--enable-parser=h263 --enable-encoder=h263p \
--enable-decoder=h263 --enable-muxer=h263 --enable-demuxer=h263 \
--enable-libmp3lame --enable-encoder=libmp3lame \
--extra-ldflags="-L$MP3LAME_HOME/libmp3lame/.libs -L$X264_HOME" --extra-cflags="-I$MP3LAME_HOME/include -I$X264_HOME" \
--disable-debug \
@ -72,6 +74,8 @@ Then run:
--disable-network \
--enable-libx264 --enable-gpl --enable-parser=h264 --enable-encoder=libx264 \
--enable-decoder=h264 --enable-muxer=h264 --enable-demuxer=h264 \
--enable-parser=h263 --enable-encoder=h263p \
--enable-decoder=h263 --enable-muxer=h263 --enable-demuxer=h263 \
--enable-libmp3lame --enable-encoder=libmp3lame \
--extra-ldflags="-L$MP3LAME_HOME/libmp3lame/.libs -L$X264_HOME" --extra-cflags="-I$MP3LAME_HOME/include -I$X264_HOME" \
--disable-debug \
@ -93,6 +97,8 @@ Note: mingw64-make failed to work (segmentation fault) that's why we fallback to
--disable-network \
--enable-libx264 --enable-gpl --enable-parser=h264 --enable-encoder=libx264 \
--enable-decoder=h264 --enable-muxer=h264 --enable-demuxer=h264 \
--enable-parser=h263 --enable-encoder=h263p \
--enable-decoder=h263 --enable-muxer=h263 --enable-demuxer=h263 \
--enable-decoder=mjpeg --enable-muxer=mjpeg --enable-demuxer=mjpeg --enable-parser=mjpeg \
--enable-libmp3lame --enable-encoder=libmp3lame \
--extra-ldflags="-L$MP3LAME_HOME/libmp3lame/.libs -L$X264_HOME" --extra-cflags="-I$MP3LAME_HOME/include -I$X264_HOME" \
@ -103,7 +109,8 @@ Note: mingw64-make failed to work (segmentation fault) that's why we fallback to
- Mac OS X
Note: removed from configure script the option to add -mdynamic-no-pic unless you compile
for i386 architecture (intel 32-bit).
for i386 architecture (intel 32-bit). For i386, remove "--enable-pic" from the following
command.
./configure \
--enable-pic \
@ -113,6 +120,8 @@ Note: mingw64-make failed to work (segmentation fault) that's why we fallback to
--disable-network \
--enable-libx264 --enable-gpl --enable-parser=h264 --enable-encoder=libx264 \
--enable-decoder=h264 --enable-muxer=h264 --enable-demuxer=h264 \
--enable-parser=h263 --enable-encoder=h263p \
--enable-decoder=h263 --enable-muxer=h263 --enable-demuxer=h263 \
--enable-libmp3lame --enable-encoder=libmp3lame \
--extra-ldflags="-fPIC -L$MP3LAME_HOME/libmp3lame/.libs -L$X264_HOME" --extra-cflags="-fPIC -I$MP3LAME_HOME/include -I$X264_HOME" \
--disable-debug \

@ -70,4 +70,26 @@ Index: libavcodec/libx264.c
+
return 0;
}
Index: libavcodec/ituh263enc.c
===================================================================
--- libavcodec/ituh263enc.c (révision 23181)
+++ libavcodec/ituh263enc.c (copie de travail)
@@ -162,7 +162,7 @@
put_bits(&s->pb, 3, 7);
put_bits(&s->pb,3,ufep); /* Update Full Extended PTYPE */
- if (format == 7)
+ if (format == 8)
put_bits(&s->pb,3,6); /* Custom Source Format */
else
put_bits(&s->pb, 3, format);
@@ -192,7 +192,7 @@
/* This should be here if PLUSPTYPE */
put_bits(&s->pb, 1, 0); /* Continuous Presence Multipoint mode: off */
- if (format == 7) {
+ if (format == 8) {
/* Custom Picture Format (CPFMT) */
s->aspect_ratio_info= ff_h263_aspect_to_info(s->avctx->sample_aspect_ratio);

@ -173,6 +173,7 @@ public class MediaUtils
VideoFormat.H261_RTP);
*/
/* H264 */
Map<String, String> h264FormatParams
= new HashMap<String, String>();
Map<String, String> h264AdvancedAttributes
@ -198,6 +199,26 @@ public class MediaUtils
Constants.H264_RTP,
h264FormatParams,
h264AdvancedAttributes);
/* H263+ */
Map<String, String> h263FormatParams
= new HashMap<String, String>();
Map<String, String> h263AdvancedAttributes
= new LinkedHashMap<String, String>();
// maximum resolution we can receive is the size of our screen device
h263FormatParams.put("CUSTOM", res.width + "," + res.height + ",2");
h263FormatParams.put("VGA", "2");
h263FormatParams.put("CIF", "1");
h263FormatParams.put("QCIF", "1");
addMediaFormats(
MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN,
"H263-1998",
MediaType.VIDEO,
Constants.H263P_RTP,
h263FormatParams,
h263AdvancedAttributes);
}
/**

@ -16,7 +16,6 @@
import javax.media.protocol.*;
import javax.media.rtp.*;
import net.java.sip.communicator.impl.neomedia.codec.*;
import net.java.sip.communicator.impl.neomedia.device.*;
import net.java.sip.communicator.impl.neomedia.transform.*;
import net.java.sip.communicator.service.neomedia.*;
@ -567,7 +566,72 @@ else if(key.equals("imageattr"))
{
outputSize = res[1];
((VideoMediaDeviceSession)getDeviceSession()).
setOutputSize(outputSize);
}
}
else if(key.equals("CIF"))
{
Dimension dim = new Dimension(352, 288);
if(outputSize == null || (outputSize.width < dim.width &&
outputSize.height < dim.height))
{
outputSize = dim;
((VideoMediaDeviceSession)getDeviceSession()).
setOutputSize(outputSize);
}
}
else if(key.equals("QCIF"))
{
Dimension dim = new Dimension(176, 144);
if(outputSize == null || (outputSize.width < dim.width &&
outputSize.height < dim.height))
{
outputSize = dim;
((VideoMediaDeviceSession)getDeviceSession()).
setOutputSize(outputSize);
}
}
else if(key.equals("VGA")) // X-lite send it
{
Dimension dim = new Dimension(640, 480);
if(outputSize == null || (outputSize.width < dim.width &&
outputSize.height < dim.height))
{
/* X-lite does not display anything if we send 640x480
* video
*/
outputSize = dim;
((VideoMediaDeviceSession)getDeviceSession()).
setOutputSize(outputSize);
}
}
else if(key.equals("CUSTOM"))
{
String args[] = value.split(",");
if(args.length < 3)
{
continue;
}
try
{
Dimension dim = new Dimension(Integer.parseInt(args[0]),
Integer.parseInt(args[1]));
if(outputSize == null || (outputSize.width < dim.width
&& outputSize.height < dim.height))
{
outputSize = dim;
((VideoMediaDeviceSession)getDeviceSession()).
setOutputSize(outputSize);
}
}
catch(Exception e)
{
}
}
}

@ -28,6 +28,8 @@ public class Constants
public static final String H264 = "h264";
public static final String H264_RTP = "h264/rtp";
public static final String H263P = "H263-1998";
public static final String H263P_RTP = "h263-1998/rtp";
/**
* Pseudo format representing DTMF tones sent over RTP.

@ -88,6 +88,10 @@ public class EncodingConfiguration
: null,
"net.java.sip.communicator.impl.neomedia.codec.audio.g722.JNIDecoder",
"net.java.sip.communicator.impl.neomedia.codec.audio.g722.JNIEncoder",
"net.java.sip.communicator.impl.neomedia.codec.video.h263p.DePacketizer",
"net.java.sip.communicator.impl.neomedia.codec.video.h263p.JNIDecoder",
"net.java.sip.communicator.impl.neomedia.codec.video.h263p.JNIEncoder",
"net.java.sip.communicator.impl.neomedia.codec.video.h263p.Packetizer",
"net.java.sip.communicator.impl.neomedia.codec.video.h264.DePacketizer",
"net.java.sip.communicator.impl.neomedia.codec.video.h264.JNIDecoder",
"net.java.sip.communicator.impl.neomedia.codec.video.h264.JNIEncoder",
@ -161,10 +165,17 @@ public void initializeFormatPreferences()
"H264",
VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
1100);
setEncodingPreference(
"H263-1998",
VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
0);
/*
setEncodingPreference(
"H263",
VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
1000);
*/
setEncodingPreference(
"JPEG",
VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
@ -382,6 +393,17 @@ public void registerCustomCodecs()
PlugInManager.removePlugIn(
"com.sun.media.codec.video.colorspace.JavaRGBConverter",
PlugInManager.CODEC);
PlugInManager.removePlugIn(
"com.sun.media.codec.video.colorspace.RGBScaler",
PlugInManager.CODEC);
/* remove JMF's H263 codec */
PlugInManager.removePlugIn(
"com.sun.media.codec.video.vh263.NativeDecoder",
PlugInManager.CODEC);
PlugInManager.removePlugIn(
"com.ibm.media.codec.video.h263.NativeEncoder",
PlugInManager.CODEC);
for (String className : CUSTOM_CODECS)
{

@ -18,8 +18,18 @@ public class FFmpeg
public static final int CODEC_FLAG_LOOP_FILTER = 0x00000800;
public static final int CODEC_FLAG_H263P_UMV = 0x01000000 ;
public static final int CODEC_FLAG_AC_PRED = 0x02000000;
public static final int CODEC_FLAG_H263P_SLICE_STRUCT = 0x10000000;
public static final int CODEC_ID_H264 = 28;
public static final int CODEC_ID_H263 = 5;
public static final int CODEC_ID_H263P = 20;
public static final int CODEC_ID_MJPEG = 8;
public static final int CODEC_ID_MP3 = 0x15000 + 1;

@ -0,0 +1,232 @@
/*
* 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.h263p;
import java.util.Arrays;
import javax.media.*;
import javax.media.format.*;
import net.java.sip.communicator.impl.neomedia.codec.*;
import net.java.sip.communicator.util.Logger;
import net.sf.fmj.media.*;
/**
* Depacketizes H.263+ RTP packets in in accord with RFC 4529 "RTP Payload
* Format for ITU-T Rec. H.263 Video".
*
* @author Sebastien Vincent
* @author Lubomir Marinov
*/
public class DePacketizer
extends AbstractCodecExt
{
/**
* The <tt>Logger</tt> used by the <tt>DePacketizer</tt> class and its
* instances for logging output.
*/
private static final Logger logger = Logger.getLogger(DePacketizer.class);
/**
* The size of the padding at the end of the output data of this
* <tt>DePacketizer</tt> expected by the H.263+ decoder.
*/
private final int outputPaddingSize = FFmpeg.FF_INPUT_BUFFER_PADDING_SIZE;
/**
* Keeps track of last (input) sequence number in order to avoid
* inconsistent data.
*/
private long lastSequenceNumber = -1;
/**
* The indicator which determines whether incomplete buffer packets are
* output from the H.263+ <tt>DePacketizer</tt> to the decoder.
*/
private static final boolean OUTPUT_INCOMPLETE_BUFFER = true;
/**
* Initializes a new <tt>DePacketizer</tt> instance which is to depacketize
* H.263+ RTP packet.
*/
public DePacketizer()
{
super(
"H263+ DePacketizer",
VideoFormat.class,
new VideoFormat[] { new VideoFormat(Constants.H263P) });
inputFormats
= new VideoFormat[] { new VideoFormat(Constants.H263P_RTP) };
}
/**
* Close the <tt>Codec</tt>.
*/
protected void doClose()
{
}
/**
* Opens this <tt>Codec</tt> and acquires the resources that it needs to
* operate. A call to {@link PlugIn#open()} on this instance will result in
* a call to <tt>doOpen</tt> only if {@link AbstractCodec#opened} is
* <tt>false</tt>. All required input and/or output formats are assumed to
* have been set on this <tt>Codec</tt> before <tt>doOpen</tt> is called.
*
* @throws ResourceUnavailableException if any of the resources that this
* <tt>Codec</tt> needs to operate cannot be acquired
* @see AbstractCodecExt#doOpen()
*/
protected void doOpen()
throws ResourceUnavailableException
{
}
/**
* Processes (depacketizes) a buffer.
*
* @param inBuffer input buffer
* @param outBuffer output buffer
* @return <tt>BUFFER_PROCESSED_OK</tt> if buffer has been successfully
* processed
*/
protected int doProcess(Buffer inBuffer, Buffer outBuffer)
{
long sequenceNumber = inBuffer.getSequenceNumber();
if ((lastSequenceNumber != -1)
&& ((sequenceNumber - lastSequenceNumber) != 1))
{
int ret = 0;
/* maybe we lost a frame somewhere or the sequence number reach
* its maximum number
*/
if (logger.isTraceEnabled())
logger.trace(
"Dropped RTP packets upto sequenceNumber "
+ lastSequenceNumber
+ " and continuing with sequenceNumber "
+ sequenceNumber);
ret = reset(outBuffer);
if ((ret & OUTPUT_BUFFER_NOT_FILLED) == 0)
{
lastSequenceNumber = -1;
return ret;
}
}
lastSequenceNumber = sequenceNumber;
byte[] in = (byte[]) inBuffer.getData();
int inLength = inBuffer.getLength();
int inOffset = inBuffer.getOffset();
int outOffset = outBuffer.getOffset();
if(inLength < 3)
{
return BUFFER_PROCESSED_FAILED;
}
boolean pBit = ((in[inOffset] & 0x04) > 0);
boolean vBit = ((in[inOffset] & 0x02) > 0);;
int plen = ((in[inOffset] & 0x01) << 5) +
((in[inOffset + 1] & 0xF8) >> 3);
int dataLength = inLength - plen - (vBit ? 1 : 0) - (pBit ? 0 : 2);
byte out[] = validateByteArraySize(outBuffer, outOffset + dataLength +
outputPaddingSize);
if(pBit)
{
out[0] = 0x00;
out[1] = 0x00;
}
if(vBit)
{
/* ignore VRC */
}
if(plen > 0)
{
if(logger.isInfoEnabled())
{
logger.info("Extra picture header present PLEN=" + plen);
}
}
System.arraycopy(in, inOffset + 2 + (vBit ? 1 : 0) + plen,
out, outOffset + (pBit ? 2 : 0), dataLength - (pBit ? 2 : 0));
padOutput(out, outOffset + dataLength);
outBuffer.setLength(outOffset + dataLength);
outBuffer.setSequenceNumber(sequenceNumber);
/*
* The RTP marker bit is set for the very last packet of the access unit
* indicated by the RTP time stamp to allow an efficient playout buffer
* handling. Consequently, we have to output it as well.
*/
if ((inBuffer.getFlags() & Buffer.FLAG_RTP_MARKER) != 0)
{
outBuffer.setFlags(outBuffer.getFlags() | Buffer.FLAG_RTP_MARKER);
outBuffer.setOffset(0);
return BUFFER_PROCESSED_OK;
}
else
{
outBuffer.setOffset(outOffset + dataLength);
return OUTPUT_BUFFER_NOT_FILLED;
}
}
/**
* Appends {@link #outputPaddingSize} number of bytes to <tt>out</tt>
* beginning at index <tt>outOffset</tt>. The specified <tt>out</tt> is
* expected to be large enough to accommodate the mentioned number of bytes.
*
* @param out the buffer in which <tt>outputPaddingSize</tt> number of bytes
* are to be written
* @param outOffset the index in <tt>outOffset</tt> at which the writing of
* <tt>outputPaddingSize</tt> number of bytes is to begin
*/
private void padOutput(byte[] out, int outOffset)
{
Arrays.fill(out, outOffset, outOffset + outputPaddingSize, (byte) 0);
}
/**
* Resets the states of this <tt>DePacketizer</tt> and a specific output
* <tt>Buffer</tt> so that they are ready to have this <tt>DePacketizer</tt>
* process input RTP payloads.
*
* @param outBuffer the output <tt>Buffer</tt> to be reset
* @return the flags such as <tt>BUFFER_PROCESSED_OK</tt> and
* <tt>OUTPUT_BUFFER_NOT_FILLED</tt> to be returned by
* {@link #process(Buffer, Buffer)}
*/
private int reset(Buffer outBuffer)
{
if (OUTPUT_INCOMPLETE_BUFFER && outBuffer.getLength() > 0)
{
Object outData = outBuffer.getData();
if (outData instanceof byte[])
{
return (BUFFER_PROCESSED_OK | INPUT_BUFFER_NOT_CONSUMED);
}
}
outBuffer.setLength(0);
return OUTPUT_BUFFER_NOT_FILLED;
}
}

@ -0,0 +1,349 @@
/*
* 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.h263p;
import java.awt.*;
import javax.media.*;
import javax.media.format.*;
import net.java.sip.communicator.impl.neomedia.codec.*;
import net.java.sip.communicator.impl.neomedia.codec.video.*;
import net.sf.fmj.media.*;
/**
* Implements a H.263+ decoder.
*
* @author Sebastien Vincent
* @author Lubomir Marinov
*/
public class JNIDecoder
extends AbstractCodec
{
/**
* Plugin name.
*/
private static final String PLUGIN_NAME = "H.263+ Decoder";
/**
* The default output <tt>VideoFormat</tt>.
*/
private static final VideoFormat[] DEFAULT_OUTPUT_FORMATS
= new VideoFormat[] { new AVFrameFormat() };
/**
* Array of output <tt>VideoFormat</tt>s.
*/
private final VideoFormat[] outputFormats;
/**
* If decoder has got a picture.
*/
private final boolean[] got_picture = new boolean[1];
/**
* The codec context native pointer we will use.
*/
private long avcontext = 0;
/**
* The decoded data is stored in avpicture in native ffmpeg format (YUV).
*/
private long avframe = 0;
/**
* The last known width of {@link #avcontext} i.e. the video output by this
* <tt>JNIDecoder</tt>. Used to detect changes in the output size.
*/
private int width = 0;
/**
* The last known height of {@link #avcontext} i.e. the video output by this
* <tt>JNIDecoder</tt>. Used to detect changes in the output size.
*/
private int height = 0;
/**
* Initializes a new <tt>JNIDecoder</tt> instance which is to decode H.263+
* encoded data into frames in YUV format.
*/
public JNIDecoder()
{
inputFormats
= new VideoFormat[] { new VideoFormat(Constants.H263P) };
outputFormats
= new VideoFormat[]
{
new AVFrameFormat(
new Dimension(
Constants.VIDEO_WIDTH,
Constants.VIDEO_HEIGHT),
ensureFrameRate(Format.NOT_SPECIFIED),
FFmpeg.PIX_FMT_YUV420P,
Format.NOT_SPECIFIED)
};
Dimension outputSize = outputFormats[0].getSize();
width = outputSize.width;
height = outputSize.height;
}
/**
* Check <tt>Format</tt>.
*
* @param format <tt>Format</tt> to check
* @return true if <tt>Format</tt> is H263P_RTP
*/
public boolean checkFormat(Format format)
{
return format.getEncoding().equals(Constants.H263P_RTP);
}
/**
* Close <tt>Codec</tt>.
*/
@Override
public synchronized void close()
{
if (opened)
{
opened = false;
super.close();
FFmpeg.avcodec_close(avcontext);
FFmpeg.av_free(avcontext);
avcontext = 0;
FFmpeg.av_free(avframe);
avframe = 0;
}
}
/**
* Ensure frame rate.
*
* @param frameRate frame rate
* @return frame rate
*/
private float ensureFrameRate(float frameRate)
{
return frameRate;
}
/**
* Get matching outputs for a specified input <tt>Format</tt>.
*
* @param in input <tt>Format</tt>
* @return array of matching outputs or null if there are no matching
* outputs.
*/
protected Format[] getMatchingOutputFormats(Format in)
{
VideoFormat ivf = (VideoFormat) in;
Dimension inSize = ivf.getSize();
Dimension outSize;
// return the default size/currently decoder and encoder
// set to transmit/receive at this size
if (inSize == null)
{
VideoFormat ovf = outputFormats[0];
if (ovf == null)
return null;
else
outSize = ovf.getSize();
}
else
outSize = inSize; // Output in same size as input.
return
new Format[]
{
new AVFrameFormat(
outSize,
ensureFrameRate(ivf.getFrameRate()),
FFmpeg.PIX_FMT_YUV420P,
Format.NOT_SPECIFIED)
};
}
/**
* Get plugin name.
*
* @return "H.263+ Decoder"
*/
@Override
public String getName()
{
return PLUGIN_NAME;
}
/**
* Get all supported output <tt>Format</tt>s.
*
* @param in input <tt>Format</tt> to determine corresponding output
* <tt>Format/tt>s
* @return array of supported <tt>Format</tt>
*/
public Format[] getSupportedOutputFormats(Format in)
{
if (in == null)
return DEFAULT_OUTPUT_FORMATS;
// mismatch input format
if (!(in instanceof VideoFormat)
|| (AbstractCodecExt.matches(in, inputFormats) == null))
return new Format[0];
// match input format
return getMatchingOutputFormats(in);
}
/**
* Inits the codec instances.
*
* @throws ResourceUnavailableException if codec initialization failed
*/
@Override
public synchronized void open()
throws ResourceUnavailableException
{
if (opened)
return;
/* from ffmpeg -formats output: "For example, the h263 decoder
* corresponds to the h263 and h263p encoders". That's why we use
* CODEC_ID_H263 for the decoder side (instead of CODEC_ID_H263P).
*/
long avcodec = FFmpeg.avcodec_find_decoder(FFmpeg.CODEC_ID_H263);
avcontext = FFmpeg.avcodec_alloc_context();
FFmpeg.avcodeccontext_set_workaround_bugs(avcontext,
FFmpeg.FF_BUG_AUTODETECT);
if (FFmpeg.avcodec_open(avcontext, avcodec) < 0)
throw new RuntimeException("Could not open codec CODEC_ID_H263");
avframe = FFmpeg.avcodec_alloc_frame();
opened = true;
super.open();
}
/**
* Decodes H.263+ media data read from a specific input <tt>Buffer</tt> into
* a specific output <tt>Buffer</tt>.
*
* @param inBuffer input <tt>Buffer</tt>
* @param outBuffer output <tt>Buffer</tt>
* @return <tt>BUFFER_PROCESSED_OK</tt> if <tt>inBuffer</tt> has been
* successfully processed
*/
public synchronized int process(Buffer inBuffer, Buffer outBuffer)
{
if (!checkInputBuffer(inBuffer))
return BUFFER_PROCESSED_FAILED;
if (isEOM(inBuffer) || !opened)
{
propagateEOM(outBuffer);
return BUFFER_PROCESSED_OK;
}
if (inBuffer.isDiscard())
{
outBuffer.setDiscard(true);
return BUFFER_PROCESSED_OK;
}
// Ask FFmpeg to decode.
got_picture[0] = false;
// TODO Take into account the offset of inputBuffer.
FFmpeg.avcodec_decode_video(
avcontext,
avframe,
got_picture,
(byte[]) inBuffer.getData(), inBuffer.getLength());
if (!got_picture[0])
{
outBuffer.setDiscard(true);
return BUFFER_PROCESSED_OK;
}
// format
int width = FFmpeg.avcodeccontext_get_width(avcontext);
int height = FFmpeg.avcodeccontext_get_height(avcontext);
if ((width > 0)
&& (height > 0)
&& ((this.width != width) || (this.height != height)))
{
this.width = width;
this.height = height;
// Output in same size and frame rate as input.
Dimension outSize = new Dimension(this.width, this.height);
VideoFormat inFormat = (VideoFormat) inBuffer.getFormat();
float outFrameRate = ensureFrameRate(inFormat.getFrameRate());
outputFormat
= new AVFrameFormat(
outSize,
outFrameRate,
FFmpeg.PIX_FMT_YUV420P,
Format.NOT_SPECIFIED);
}
outBuffer.setFormat(outputFormat);
// data
Object out = outBuffer.getData();
if (!(out instanceof AVFrame) || (((AVFrame) out).getPtr() != avframe))
outBuffer.setData(new AVFrame(avframe));
// timeStamp
long pts = FFmpeg.AV_NOPTS_VALUE; // TODO avframe_get_pts(avframe);
if (pts == FFmpeg.AV_NOPTS_VALUE)
outBuffer.setTimeStamp(Buffer.TIME_UNKNOWN);
else
{
outBuffer.setTimeStamp(pts);
int outFlags = outBuffer.getFlags();
outFlags |= Buffer.FLAG_RELATIVE_TIME;
outFlags &= ~(Buffer.FLAG_RTP_TIME | Buffer.FLAG_SYSTEM_TIME);
outBuffer.setFlags(outFlags);
}
return BUFFER_PROCESSED_OK;
}
/**
* Sets the <tt>Format</tt> of the media data to be input for processing in
* this <tt>Codec</tt>.
*
* @param format the <tt>Format</tt> of the media data to be input for
* processing in this <tt>Codec</tt>
* @return the <tt>Format</tt> of the media data to be input for processing
* in this <tt>Codec</tt> if <tt>format</tt> is compatible with this
* <tt>Codec</tt>; otherwise, <tt>null</tt>
*/
@Override
public Format setInputFormat(Format format)
{
Format setFormat = super.setInputFormat(format);
if (setFormat != null)
reset();
return setFormat;
}
}

@ -0,0 +1,463 @@
/*
* 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.h263p;
import java.awt.*;
import javax.media.*;
import javax.media.format.*;
import net.java.sip.communicator.impl.neomedia.codec.*;
import net.sf.fmj.media.*;
/**
* Implements a H.263+ encoder.
*
* @author Sebastien Vincent
* @author Lubomir Marinov
*/
public class JNIEncoder
extends AbstractCodec
{
/**
* The frame rate to be assumed by <tt>JNIEncoder</tt> instance in the
* absence of any other frame rate indication.
*/
private static final int DEFAULT_FRAME_RATE = 30;
/**
* Default output formats.
*/
private static final Format[] DEFAULT_OUTPUT_FORMATS
= { new VideoFormat(Constants.H263P) };
/**
* Key frame every 300 frames.
*/
private static final int IFRAME_INTERVAL = 300;
/**
* Name of the code.
*/
private static final String PLUGIN_NAME = "H.263+ Encoder";
/**
* The codec we will use.
*/
private long avcontext = 0;
/**
* The encoded data is stored in avpicture.
*/
private long avframe = 0;
/**
* We use this buffer to supply data to encoder.
*/
private byte[] encFrameBuffer = null;
/**
* The supplied data length.
*/
private int encFrameLen = 0;
/**
* The raw frame buffer.
*/
private long rawFrameBuffer = 0;
/**
* Next interval for an automatic keyframe.
*/
private int framesSinceLastIFrame = IFRAME_INTERVAL + 1;
/**
* Initializes a new <tt>JNIEncoder</tt> instance.
*/
public JNIEncoder()
{
inputFormats
= new Format[]
{
new YUVFormat(
null,
Format.NOT_SPECIFIED,
Format.byteArray,
DEFAULT_FRAME_RATE,
YUVFormat.YUV_420,
Format.NOT_SPECIFIED, Format.NOT_SPECIFIED,
0, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED)
};
inputFormat = null;
outputFormat = null;
}
/**
* Closes this <tt>Codec</tt>.
*/
@Override
public synchronized void close()
{
if (opened)
{
opened = false;
super.close();
FFmpeg.avcodec_close(avcontext);
FFmpeg.av_free(avcontext);
avcontext = 0;
FFmpeg.av_free(avframe);
avframe = 0;
FFmpeg.av_free(rawFrameBuffer);
rawFrameBuffer = 0;
encFrameBuffer = null;
}
}
/**
* Gets the matching output formats for a specific format.
*
* @param in input format
* @return array for formats matching input format
*/
private Format[] getMatchingOutputFormats(Format in)
{
VideoFormat videoIn = (VideoFormat) in;
return
new VideoFormat[]
{
new VideoFormat(
Constants.H263P,
videoIn.getSize(),
Format.NOT_SPECIFIED,
Format.byteArray,
videoIn.getFrameRate())
};
}
/**
* Gets the name of this <tt>Codec</tt>.
*
* @return codec name
*/
@Override
public String getName()
{
return PLUGIN_NAME;
}
/**
* Returns the list of formats supported at the output.
*
* @param in input <tt>Format</tt> to determine corresponding output
* <tt>Format/tt>s
* @return array of formats supported at output
*/
public Format[] getSupportedOutputFormats(Format in)
{
// null input format
if (in == null)
return DEFAULT_OUTPUT_FORMATS;
// mismatch input format
if (!(in instanceof VideoFormat)
|| (null == AbstractCodecExt.matches(in, inputFormats)))
return new Format[0];
return getMatchingOutputFormats(in);
}
/**
* Opens this <tt>Codec</tt>.
*/
@Override
public synchronized void open()
throws ResourceUnavailableException
{
if (opened)
return;
if (inputFormat == null)
throw new ResourceUnavailableException("No input format selected");
if (outputFormat == null)
throw new ResourceUnavailableException("No output format selected");
VideoFormat outputVideoFormat = (VideoFormat) outputFormat;
Dimension size = outputVideoFormat.getSize();
int width = size.width;
int height = size.height;
long avcodec = FFmpeg.avcodec_find_encoder(FFmpeg.CODEC_ID_H263P);
avcontext = FFmpeg.avcodec_alloc_context();
System.out.println("transmit " + width + "x" + height);
FFmpeg.avcodeccontext_set_pix_fmt(avcontext, FFmpeg.PIX_FMT_YUV420P);
FFmpeg.avcodeccontext_set_size(avcontext, width, height);
FFmpeg.avcodeccontext_set_qcompress(avcontext, 0.6f);
int bitRate = 256000;
int frameRate = (int) outputVideoFormat.getFrameRate();
if (frameRate == Format.NOT_SPECIFIED)
frameRate = DEFAULT_FRAME_RATE;
// average bit rate
FFmpeg.avcodeccontext_set_bit_rate(avcontext, bitRate);
FFmpeg.avcodeccontext_set_bit_rate_tolerance(avcontext,
bitRate / (frameRate - 1));
//FFmpeg.avcodeccontext_set_rc_max_rate(avcontext, bitRate);
//FFmpeg.avcodeccontext_set_sample_aspect_ratio(avcontext, 0, 0);
// time_base should be 1 / frame rate
FFmpeg.avcodeccontext_set_time_base(avcontext, 1, frameRate);
//FFmpeg.avcodeccontext_set_quantizer(avcontext, 10, 51, 4);
FFmpeg.avcodeccontext_set_mb_decision(avcontext,
FFmpeg.FF_MB_DECISION_SIMPLE);
//FFmpeg.avcodeccontext_set_rc_eq(avcontext, "blurCplx^(1-qComp)");
FFmpeg.avcodeccontext_add_flags(avcontext,
FFmpeg.CODEC_FLAG_LOOP_FILTER);
FFmpeg.avcodeccontext_add_flags(avcontext,
FFmpeg.CODEC_FLAG_AC_PRED);
FFmpeg.avcodeccontext_add_flags(avcontext,
FFmpeg.CODEC_FLAG_H263P_UMV);
FFmpeg.avcodeccontext_add_flags(avcontext,
FFmpeg.CODEC_FLAG_H263P_SLICE_STRUCT);
FFmpeg.avcodeccontext_set_me_method(avcontext, 6);
FFmpeg.avcodeccontext_set_me_subpel_quality(avcontext, 2);
FFmpeg.avcodeccontext_set_me_range(avcontext, 18);
FFmpeg.avcodeccontext_set_me_cmp(avcontext, FFmpeg.FF_CMP_CHROMA);
FFmpeg.avcodeccontext_set_scenechange_threshold(avcontext, 40);
// Constant quality mode (also known as constant ratefactor)
//FFmpeg.avcodeccontext_set_crf(avcontext, 0);
//FFmpeg.avcodeccontext_set_rc_buffer_size(avcontext, 0);
FFmpeg.avcodeccontext_set_gop_size(avcontext, IFRAME_INTERVAL);
//FFmpeg.avcodeccontext_set_i_quant_factor(avcontext, 1f / 1.4f);
//FFmpeg.avcodeccontext_set_refs(avcontext, 2);
//FFmpeg.avcodeccontext_set_trellis(avcontext, 2);
if (FFmpeg.avcodec_open(avcontext, avcodec) < 0)
{
throw
new ResourceUnavailableException(
"Could not open codec. (size= "
+ width + "x" + height
+ ")");
}
encFrameLen = (width * height * 3) / 2;
rawFrameBuffer = FFmpeg.av_malloc(encFrameLen);
avframe = FFmpeg.avcodec_alloc_frame();
int sizeInBytes = width * height;
FFmpeg.avframe_set_data(
avframe,
rawFrameBuffer,
sizeInBytes,
sizeInBytes / 4);
FFmpeg.avframe_set_linesize(avframe, width, width / 2, width / 2);
encFrameBuffer = new byte[encFrameLen];
opened = true;
super.open();
}
/**
* Processes/encodes a buffer.
*
* @param inBuffer input buffer
* @param outBuffer output buffer
* @return <tt>BUFFER_PROCESSED_OK</tt> if buffer has been successfully
* processed
*/
public synchronized int process(Buffer inBuffer, Buffer outBuffer)
{
if (isEOM(inBuffer))
{
propagateEOM(outBuffer);
reset();
return BUFFER_PROCESSED_OK;
}
if (inBuffer.isDiscard())
{
outBuffer.setDiscard(true);
reset();
return BUFFER_PROCESSED_OK;
}
Format inFormat = inBuffer.getFormat();
if ((inFormat != inputFormat) && !inFormat.matches(inputFormat))
setInputFormat(inFormat);
if (inBuffer.getLength() < 3)
{
outBuffer.setDiscard(true);
reset();
return BUFFER_PROCESSED_OK;
}
// copy data to avframe
FFmpeg.memcpy(
rawFrameBuffer,
(byte[]) inBuffer.getData(), inBuffer.getOffset(),
encFrameLen);
if (framesSinceLastIFrame >= IFRAME_INTERVAL)
{
FFmpeg.avframe_set_key_frame(avframe, true);
framesSinceLastIFrame = 0;
}
else
{
framesSinceLastIFrame++;
FFmpeg.avframe_set_key_frame(avframe, false);
}
// encode data
int encLen
= FFmpeg.avcodec_encode_video(
avcontext,
encFrameBuffer, encFrameLen,
avframe);
/*
* Do not always allocate a new data array for outBuffer, try to reuse
* the existing one if it is suitable.
*/
Object outData = outBuffer.getData();
byte[] out;
if (outData instanceof byte[])
{
out = (byte[]) outData;
if (out.length < encLen)
out = null;
}
else
out = null;
if (out == null)
out = new byte[encLen];
System.arraycopy(encFrameBuffer, 0, out, 0, encLen);
outBuffer.setData(out);
outBuffer.setLength(encLen);
outBuffer.setOffset(0);
outBuffer.setTimeStamp(inBuffer.getTimeStamp());
return BUFFER_PROCESSED_OK;
}
/**
* Sets the input format.
*
* @param in format to set
* @return format
*/
@Override
public Format setInputFormat(Format in)
{
// mismatch input format
if (!(in instanceof VideoFormat)
|| (null == AbstractCodecExt.matches(in, inputFormats)))
return null;
YUVFormat yuv = (YUVFormat) in;
if (yuv.getOffsetU() > yuv.getOffsetV())
return null;
Dimension size = yuv.getSize();
if (size == null)
size = new Dimension(Constants.VIDEO_WIDTH, Constants.VIDEO_HEIGHT);
int strideY = size.width;
int strideUV = strideY / 2;
int offsetU = strideY * size.height;
int offsetV = offsetU + strideUV * size.height / 2;
int yuvMaxDataLength = (strideY + strideUV) * size.height;
inputFormat
= new YUVFormat(
size,
yuvMaxDataLength + FFmpeg.FF_INPUT_BUFFER_PADDING_SIZE,
Format.byteArray,
yuv.getFrameRate(),
YUVFormat.YUV_420,
strideY, strideUV,
0, offsetU, offsetV);
// Return the selected inputFormat
return inputFormat;
}
/**
* Sets the <tt>Format</tt> in which this <tt>Codec</tt> is to output media
* data.
*
* @param out the <tt>Format</tt> in which this <tt>Codec</tt> is to
* output media data
* @return the <tt>Format</tt> in which this <tt>Codec</tt> is currently
* configured to output media data or <tt>null</tt> if <tt>format</tt> was
* found to be incompatible with this <tt>Codec</tt>
*/
@Override
public Format setOutputFormat(Format out)
{
// mismatch output format
if (!(out instanceof VideoFormat)
|| (null
== AbstractCodecExt.matches(
out,
getMatchingOutputFormats(inputFormat))))
return null;
VideoFormat videoOut = (VideoFormat) out;
Dimension outSize = videoOut.getSize();
if (outSize == null)
{
Dimension inSize = ((VideoFormat) inputFormat).getSize();
outSize
= (inSize == null)
? new Dimension(
Constants.VIDEO_WIDTH,
Constants.VIDEO_HEIGHT)
: inSize;
}
outputFormat
= new VideoFormat(
videoOut.getEncoding(),
outSize,
Format.NOT_SPECIFIED,
Format.byteArray,
videoOut.getFrameRate());
// Return the selected outputFormat
return outputFormat;
}
}

@ -0,0 +1,419 @@
/*
* 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.h263p;
import java.awt.*;
import java.util.*;
import java.util.List; // disambiguation
import javax.media.*;
import javax.media.format.*;
import net.java.sip.communicator.impl.neomedia.codec.*;
import net.sf.fmj.media.*;
/**
* Packetizes H.263+ encoded data into RTP packets in accord with RFC 4529
* "RTP Payload Format for ITU-T Rec. H.263 Video".
*
* @author Sebastien Vincent
* @author Lubomir Marinov
*/
public class Packetizer
extends AbstractPacketizer
{
/**
* Array of default output formats.
*/
private static final Format[] DEFAULT_OUTPUT_FORMATS
= { new VideoFormat(Constants.H263P_RTP) };
/**
* Maximum payload size without the headers.
*/
public static final int MAX_PAYLOAD_SIZE = 1024;
/**
* Name of the plugin.
*/
private static final String PLUGIN_NAME = "H263+ Packetizer";
/**
* The sequence number of the next RTP packet to be output by this
* <tt>Packetizer</tt>.
*/
private int sequenceNumber = 0;
/**
* The list of H263+ "Start code" video packets to be sent as payload in RTP
* packets.
*/
private final List<byte[]> videoPkts = new LinkedList<byte[]>();
/**
* The timeStamp of the RTP packets in which H263+ packets are to be sent.
*/
private long timeStamp = 0;
/**
* Initializes a new <tt>Packetizer</tt> instance which is to packetize
* H.263+ encoded data into RTP packets in accord with
* RFC 4529 "RTP Payload Format for ITU-T Rec. H.263 Video".
*/
public Packetizer()
{
inputFormats = new Format[] { new VideoFormat(Constants.H263P) };
inputFormat = null;
outputFormat = null;
}
/**
* Get the matching output formats for a specific format.
*
* @param in input format
* @return array for formats matching input format
*/
private Format[] getMatchingOutputFormats(Format in)
{
VideoFormat videoIn = (VideoFormat) in;
Dimension inSize = videoIn.getSize();
return
new VideoFormat[]
{
new VideoFormat(
Constants.H263P_RTP,
inSize,
Format.NOT_SPECIFIED,
Format.byteArray,
videoIn.getFrameRate())
};
}
/**
* Get codec name.
*
* @return codec name
*/
@Override
public String getName()
{
return PLUGIN_NAME;
}
/**
* Return the list of formats supported at the output.
* @param in input <tt>Format</tt> to determine corresponding output
* <tt>Format/tt>s
* @return array of formats supported at output
*/
public Format[] getSupportedOutputFormats(Format in)
{
// null input format
if (in == null)
return DEFAULT_OUTPUT_FORMATS;
// mismatch input format
if (!(in instanceof VideoFormat)
|| (null == AbstractCodecExt.matches(in, inputFormats)))
{
return new Format[0];
}
return getMatchingOutputFormats(in);
}
/**
* Open this <tt>Packetizer</tt>.
*
* @throws ResourceUnavailableException if something goes wrong during
* initialization of the Packetizer.
*/
@Override
public synchronized void open()
throws ResourceUnavailableException
{
if (!opened)
{
videoPkts.clear();
sequenceNumber = 0;
super.open();
opened = true;
}
}
/**
* Close this <tt>Packetizer</tt>.
*/
@Override
public synchronized void close()
{
if (opened)
{
videoPkts.clear();
opened = false;
super.close();
}
}
/**
* Sets the input format.
*
* @param in format to set
* @return format
*/
@Override
public Format setInputFormat(Format in)
{
/*
* Return null if the specified input Format is incompatible with this
* Packetizer.
*/
if (!(in instanceof VideoFormat)
|| null == AbstractCodecExt.matches(in, inputFormats))
return null;
inputFormat = in;
return in;
}
/**
* Sets the <tt>Format</tt> in which this <tt>Codec</tt> is to output media
* data.
*
* @param out the <tt>Format</tt> in which this <tt>Codec</tt> is to
* output media data
* @return the <tt>Format</tt> in which this <tt>Codec</tt> is currently
* configured to output media data or <tt>null</tt> if <tt>format</tt> was
* found to be incompatible with this <tt>Codec</tt>
*/
@Override
public Format setOutputFormat(Format out)
{
/*
* Return null if the specified output Format is incompatible with this
* Packetizer.
*/
if (!(out instanceof VideoFormat)
|| (null
== AbstractCodecExt.matches(
out,
getMatchingOutputFormats(inputFormat))))
return null;
VideoFormat videoOut = (VideoFormat) out;
Dimension outSize = videoOut.getSize();
if (outSize == null)
{
Dimension inSize = ((VideoFormat) inputFormat).getSize();
outSize
= (inSize == null)
? new Dimension(
Constants.VIDEO_WIDTH,
Constants.VIDEO_HEIGHT)
: inSize;
}
outputFormat
= new VideoFormat(
videoOut.getEncoding(),
outSize,
outSize.width * outSize.height,
Format.byteArray,
videoOut.getFrameRate());
// Return the outputFormat which is actually set.
return outputFormat;
}
/**
* Processes (packetize) a buffer.
*
* @param inBuffer input buffer
* @param outBuffer output buffer
* @return <tt>BUFFER_PROCESSED_OK</tt> if buffer has been successfully
* processed
*/
@Override
public int process(Buffer inBuffer, Buffer outBuffer)
{
int inLength = inBuffer.getLength();
byte inData[] = (byte[])inBuffer.getData();
int inOffset = inBuffer.getOffset();
boolean pktAdded = false;
if (videoPkts.size() > 0)
{
byte[] pktData = videoPkts.remove(0);
// Send the packet.
outBuffer.setData(pktData);
outBuffer.setLength(pktData.length);
outBuffer.setOffset(0);
outBuffer.setTimeStamp(timeStamp);
outBuffer.setSequenceNumber(sequenceNumber++);
// If there are other packets, send them as well.
if(videoPkts.size() > 0)
{
return (BUFFER_PROCESSED_OK | INPUT_BUFFER_NOT_CONSUMED);
}
else
{
// It's the last packet of the current frame so mark it.
outBuffer.setFlags(
outBuffer.getFlags() | Buffer.FLAG_RTP_MARKER);
return BUFFER_PROCESSED_OK;
}
}
if (isEOM(inBuffer))
{
propagateEOM(outBuffer);
reset();
return BUFFER_PROCESSED_OK;
}
if (inBuffer.isDiscard())
{
outBuffer.setDiscard(true);
reset();
return BUFFER_PROCESSED_OK;
}
Format inFormat = inBuffer.getFormat();
if ((inFormat != inputFormat) && !inFormat.matches(inputFormat))
setInputFormat(inFormat);
int endIndex = inOffset + inLength;
int beginIndex = findStartcode(inData, inOffset, endIndex);
if (beginIndex < endIndex)
{
for (int nextBeginIndex;
beginIndex < endIndex;
beginIndex = nextBeginIndex + 3)
{
nextBeginIndex = findStartcode(inData, beginIndex + 3,
endIndex);
int length = nextBeginIndex - beginIndex;
if (length > 0)
{
pktAdded
= packetize(inData, beginIndex, length)
|| pktAdded;
beginIndex += length;
}
}
}
timeStamp = inBuffer.getTimeStamp();
if(pktAdded)
{
return process(inBuffer, outBuffer);
}
else
{
/* first frame is not a synchronization point, discard ?*/
return BUFFER_PROCESSED_FAILED;
}
}
/**
* Packetizes H.263+ encoded data so that it becomes ready to be sent as the
* payload of RTP packets.
*
* @param data the bytes which contain the H.263+ encoded data to be
* packetized
* @param offset the offset of H.263+ encoded data to be packetized begins
* @param length the length of the H.263+ encoded data starting at offset
* @return <tt>true</tt> if at least one RTP packet payload has been
* packetized i.e. prepared for sending; otherwise, <tt>false</tt>
*/
private boolean packetize(byte[] data, int offset, int length)
{
boolean pktAdded = false;
while(length > 0)
{
boolean isPsc = false;
int pos = 0;
int maxPayloadLength = MAX_PAYLOAD_SIZE;
byte pkt[] = null;
int payloadLength = 0;
/* is we are at synchronization point (PSC, GSBC, EOS, EOSBS) */
if(data.length > 3 && data[offset] == 0x00 &&
data[offset + 1] == 0x00)
{
isPsc = true;
pos = 2;
}
else
{
maxPayloadLength -= 2;
}
if(length > maxPayloadLength)
{
payloadLength = maxPayloadLength;
}
else
{
payloadLength = length;
}
pkt = new byte[payloadLength + (isPsc ? 0 : 2)];
/* add H263+ payload header */
/* no VRC and no extra picture header */
pkt[0] = (byte)(isPsc ? 0x04 : 0x00);
pkt[1] = 0x00;
System.arraycopy(data, offset + pos, pkt, 2, payloadLength - pos);
pktAdded = videoPkts.add(pkt) || pktAdded;
offset += payloadLength;
length -= payloadLength;
}
return pktAdded;
}
/**
* Finds the index in <tt>byteStream</tt> at which a Picture Start code
* begins.
*
* @param byteStream the H.263+ encoded byte stream
* @param beginIndex the inclusive index in <tt>byteStream</tt> at which the
* search is to begin
* @param endIndex the exclusive index in <tt>byteStream</tt> at which the
* search is to end
* @return the index in <tt>byteStream</tt> at which the Picture Start code
* begins, otherwise, <tt>endIndex</tt>
*/
private static int findStartcode(byte[] byteStream, int beginIndex,
int endIndex)
{
for (; beginIndex < (endIndex - 3); beginIndex++)
if((byteStream[beginIndex] == 0)
&& (byteStream[beginIndex + 1] == 0)
&& ((byteStream[beginIndex + 2] & (byte)0x80) == -128))
{
return beginIndex;
}
return endIndex;
}
}

@ -13,7 +13,6 @@
import net.java.sip.communicator.impl.neomedia.*;
import net.java.sip.communicator.impl.neomedia.codec.*;
import net.java.sip.communicator.impl.neomedia.codec.video.*;
import net.java.sip.communicator.util.*;
import net.sf.fmj.media.*;
@ -345,7 +344,7 @@ protected void doOpen()
lastTimeStamp = -1;
}
/**
* Processes (depacketize) a buffer.
* Processes (depacketizes) a buffer.
*
* @param inBuffer input buffer
* @param outBuffer output buffer

@ -14,7 +14,6 @@
import net.java.sip.communicator.service.neomedia.event.*;
import net.java.sip.communicator.impl.neomedia.codec.*;
import net.java.sip.communicator.impl.neomedia.codec.video.*;
import net.sf.fmj.media.*;
/**

@ -166,6 +166,9 @@ public Format[] getSupportedOutputFormats(Format in)
/**
* Open this <tt>Packetizer</tt>.
*
* @throws ResourceUnavailableException if something goes wrong during
* initialization of the Packetizer.
*/
@Override
public synchronized void open()

@ -1055,6 +1055,19 @@ public void setRemoteSSRC(long remoteSSRC)
@Override
protected void setProcessorFormat(Processor processor, Format format)
{
if(format.getEncoding().equals("h263-1998/rtp"))
{
/* if no output size has been defined, it means that no SDP's fmtp
* has been found with QCIF, CIF, VGA or CUSTOM elements
*
* Let's choose QCIF size (176x144)
*/
if(outputSize == null)
{
outputSize = new Dimension(176, 144);
}
}
/*
* Add a size in the output format. As VideoFormat has no setter, we
* recreate the object. Also check whether capture device can output

@ -219,7 +219,7 @@ public MediaFormat createMediaFormat(String encoding,
Map<String, String> advancedParameters
= new HashMap<String, String>();
formatParameters.putAll(mediaFormat.getFormatParameters());
//formatParameters.putAll(mediaFormat.getFormatParameters());
formatParameters.putAll(formatParams);
if(advancedParams != null)

Loading…
Cancel
Save