package javaforce.voip; /** * Encodes/Decodes RTP/H263+ packets (H263-1998) * * Payload type is Dynamic * * SDP Syntax = "H263-1998" * * http://tools.ietf.org/html/rfc4629 * * @author pquiring */ import java.util.*; import javaforce.*; public class RTPH263_1998 { public RTPH263_1998() { ssrc = new Random().nextInt(); } private int find_best_length(byte data[], int offset, int length) { //see if there is a 0,0,x and return a length to that //this way the next packet will start at a resync point for(int a=1;a<length-3;a++) { if (data[offset + a] == 0 && data[offset + a + 1] == 0 && data[offset + a + 2] != 0) return a; } return length; } /** Encodes raw H.263 data into multiple RTP packets. */ public byte[][] encode(byte data[], int x, int y, int id) { ArrayList<byte[]> packets = new ArrayList<byte[]>(); int len = data.length; int packetLength; int offset = 0; byte packet[]; boolean P; //was 0,0 stripped off? while (len > 0) { P = false; if (len > 2 && data[offset] == 0 && data[offset + 1] == 0) { P = true; offset += 2; len -= 2; } if (len > mtu) { packetLength = find_best_length(data, offset, len); } else { packetLength = len; } packet = new byte[packetLength + 12 + 2]; //12=RTP.length 2=rtp_h263+_header.length RTPChannel.buildHeader(packet, id, seqnum++, timestamp, ssrc, len == packetLength); //build H.263 header (2 bytes) packet[12] = (byte)(P ? 0x04 : 0x00); // packet[13] = 0x00; System.arraycopy(data, offset, packet, 12 + 2, packetLength); offset += packetLength; len -= packetLength; packets.add(packet); } timestamp += 100; //??? 10 fps ??? return packets.toArray(new byte[0][0]); } /** * Returns last full packet. */ public byte[] decode(byte rtp[]) { if (rtp.length < 12 + 2) return null; //bad packet if (partial == null) { partial = new byte[0]; } int h263Length = rtp.length - 12 - 2; boolean P = (rtp[12] & 0x04) == 0x04; int partialLength = partial.length; partial = JF.copyOf(partial, partial.length + (P ? 2 : 0) + h263Length); //if P is true a 0,0 is left between last packet and this packet System.arraycopy(rtp, 12 + 2, partial, partialLength + (P ? 2 : 0), h263Length); if ((rtp[1] & 0x80) == 0x80) { //RTP.M flag byte ret[] = partial; partial = null; return ret; } return null; } //mtu = 1500 - 14(ethernet) - 20(ip) - 8(udp) - 12(rtp) - 2(rtp_h263_header) = 1444 bytes payload per packet private static final int mtu = 1444; private int seqnum; private int timestamp; private final int ssrc; private byte partial[]; }