package javaforce.voip; /** * Encodes/Decodes RTP/VP8 packets * * http://tools.ietf.org/html/draft-ietf-payload-vp8-01 * * @author pquiring */ import java.util.*; import javaforce.*; public class RTPVP8 { public RTPVP8() { ssrc = new Random().nextInt(); } /** Encodes raw VP8 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[]; while (len > 0) { if (len > mtu) { packetLength = mtu; } else { packetLength = len; } packet = new byte[packetLength + 1 + 12]; //1=VP8 header, 12=RTP.length RTPChannel.buildHeader(packet, id, seqnum++, timestamp, ssrc, len == packetLength); packet[12] = (byte)(packets.size() == 0 ? 0x10 : 0); //X R N S PartID System.arraycopy(data, offset, packet, 13, packetLength); packets.add(packet); offset += packetLength; len -= packetLength; } 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 int vp8Length = rtp.length - 12; int payloadOffset = 12; if (partial == null) { partial = new byte[0]; } byte x = rtp[12]; //X R N S PartID payloadOffset++; vp8Length--; if ((x & 0x80) == 0x80) { byte ilt = rtp[13]; //I L T RSV-A payloadOffset++; vp8Length--; if ((ilt & 0x80) == 0x80) { //picture ID payloadOffset++; vp8Length--; } if ((ilt & 0x40) == 0x40) { //TL0PICIDX payloadOffset++; vp8Length--; } if ((ilt & 0x20) == 0x20) { //TID RSV-B payloadOffset++; vp8Length--; } } //copy to partial int partialLength = partial.length; partial = Arrays.copyOf(partial, partial.length + vp8Length); System.arraycopy(rtp, payloadOffset, partial, partialLength, vp8Length); int thisseqnum = RTPChannel.getseqnum(rtp, 0); if (lastseqnum != -1 && thisseqnum != lastseqnum + 1) { JFLog.log("VP8:Received packet out of order, discarding frame."); partial = null; lastseqnum = -1; return null; } lastseqnum = thisseqnum; if ((rtp[1] & 0x80) == 0x80) { //check RTP.M flag byte full[] = partial; partial = null; lastseqnum = -1; return full; } return null; } //mtu = 1500 - 14(ethernet) - 20(ip) - 8(udp) - 12(rtp) - 1 (VP8) = 1445 bytes payload per packet private static final int mtu = 1445; private int seqnum; private int timestamp; private final int ssrc; private byte partial[]; private int lastseqnum = -1; }